@@ -25,6 +25,7 @@ import {
2525 EdgeEncodeUri ,
2626 EdgeGetReceiveAddressOptions ,
2727 EdgeGetTransactionsOptions ,
28+ EdgeOtherMethods ,
2829 EdgeParsedUri ,
2930 EdgePaymentProtocolInfo ,
3031 EdgeReceiveAddress ,
@@ -45,7 +46,8 @@ import {
4546} from '../../../types/types'
4647import { makeMetaTokens } from '../../account/custom-tokens'
4748import { splitWalletInfo } from '../../login/splitting'
48- import { toApiInput } from '../../root-pixie'
49+ import { getCurrencyTools } from '../../plugins/plugins-selectors'
50+ import { RootProps , toApiInput } from '../../root-pixie'
4951import { makeStorageWalletApi } from '../../storage/storage-api'
5052import { getCurrencyMultiplier } from '../currency-selectors'
5153import {
@@ -92,36 +94,84 @@ type SavedSpendTargets = EdgeTransaction['spendTargets']
9294 */
9395export function makeCurrencyWalletApi (
9496 input : CurrencyWalletInput ,
95- engine : EdgeCurrencyEngine ,
96- tools : EdgeCurrencyTools ,
9797 publicWalletInfo : EdgeWalletInfo
9898) : EdgeCurrencyWallet {
9999 const ai = toApiInput ( input )
100+ const { walletId } = input . props
100101 const { accountId, pluginId, walletInfo } = input . props . walletState
101102 const plugin = input . props . state . plugins . currency [ pluginId ]
102103 const { unsafeBroadcastTx = false , unsafeMakeSpend = false } =
103104 plugin . currencyInfo
104105
106+ /**
107+ * The wallet API object exists before the engine does,
108+ * so engine-backed methods wait for the engine internally.
109+ * Bail out if the wallet is deleted mid-wait, and re-throw
110+ * `engineFailure` so a broken plugin surfaces as a rejected
111+ * method call instead of a hang.
112+ */
113+ function getEngine ( ) : Promise < EdgeCurrencyEngine > {
114+ return ai . waitFor ( ( props : RootProps ) : EdgeCurrencyEngine | undefined => {
115+ if ( props . state . currency . wallets [ walletId ] == null ) {
116+ throw new Error ( `Wallet id ${ walletId } does not exist in this account` )
117+ }
118+ const { engineFailure } = props . state . currency . wallets [ walletId ]
119+ if ( engineFailure != null ) throw engineFailure
120+ return props . output . currency . wallets [ walletId ] ?. engine
121+ } )
122+ }
123+
124+ async function getTools ( ) : Promise < EdgeCurrencyTools > {
125+ return await getCurrencyTools ( ai , pluginId )
126+ }
127+
128+ /**
129+ * Methods that write synced-repo files need the storage wallet,
130+ * not the engine. The repo loads well before the engine,
131+ * so this wait is much shorter than `getEngine`.
132+ */
133+ function getStorage ( ) : Promise < true > {
134+ return ai . waitFor ( ( props : RootProps ) : true | undefined => {
135+ if ( props . state . currency . wallets [ walletId ] == null ) {
136+ throw new Error ( `Wallet id ${ walletId } does not exist in this account` )
137+ }
138+ const { engineFailure } = props . state . currency . wallets [ walletId ]
139+ if ( engineFailure != null ) throw engineFailure
140+ if ( props . state . storageWallets [ walletId ] != null ) return true
141+ } )
142+ }
143+
105144 const storageWalletApi = makeStorageWalletApi ( ai , walletInfo )
106145
107146 const fakeCallbacks = makeCurrencyWalletCallbacks ( input )
108147
109- const otherMethods : { [ name : string ] : ( ...args : any [ ] ) => any } = { }
110- if ( engine . otherMethods != null ) {
111- for ( const name of Object . keys ( engine . otherMethods ) ) {
112- const method = engine . otherMethods [ name ]
113- if ( typeof method !== 'function' ) continue
114- otherMethods [ name ] = method
148+ // The core guarantees `otherMethods` is `{}` (never `undefined`) before
149+ // the engine exists, so property probes stay safe on the GUI side.
150+ // Once the engine lands, the pixie watcher's `update` propagates the
151+ // engine's bridgified methods through the same getter:
152+ const emptyOtherMethods = bridgifyObject ( { } )
153+ let engineOtherMethods : EdgeOtherMethods | undefined
154+
155+ function makeEngineOtherMethods (
156+ engine : EdgeCurrencyEngine
157+ ) : EdgeOtherMethods {
158+ const otherMethods : { [ name : string ] : ( ...args : any [ ] ) => any } = { }
159+ if ( engine . otherMethods != null ) {
160+ for ( const name of Object . keys ( engine . otherMethods ) ) {
161+ const method = engine . otherMethods [ name ]
162+ if ( typeof method !== 'function' ) continue
163+ otherMethods [ name ] = method
164+ }
115165 }
116- }
117- if ( engine . otherMethodsWithKeys != null ) {
118- for ( const name of Object . keys ( engine . otherMethodsWithKeys ) ) {
119- const method = engine . otherMethodsWithKeys [ name ]
120- if ( typeof method !== 'function' ) continue
121- otherMethods [ name ] = ( ... args ) => method ( walletInfo . keys , ... args )
166+ if ( engine . otherMethodsWithKeys != null ) {
167+ for ( const name of Object . keys ( engine . otherMethodsWithKeys ) ) {
168+ const method = engine . otherMethodsWithKeys [ name ]
169+ if ( typeof method !== 'function' ) continue
170+ otherMethods [ name ] = ( ... args ) => method ( walletInfo . keys , ... args )
171+ }
122172 }
173+ return bridgifyObject ( otherMethods )
123174 }
124- bridgifyObject ( otherMethods )
125175
126176 const out : EdgeCurrencyWallet & InternalWalletMethods = {
127177 on : onMethod ,
@@ -143,8 +193,13 @@ export function makeCurrencyWalletApi(
143193 get localDisklet ( ) : Disklet {
144194 return storageWalletApi . localDisklet
145195 } ,
146- publicWalletInfo,
196+ get publicWalletInfo ( ) : EdgeWalletInfo {
197+ // The cache-loaded value may be upgraded (re-derived) later,
198+ // so always serve the latest one from Redux:
199+ return input . props . walletState . publicWalletInfo ?? publicWalletInfo
200+ } ,
147201 async sync ( ) : Promise < void > {
202+ await getStorage ( )
148203 await storageWalletApi . sync ( )
149204 } ,
150205 get type ( ) : string {
@@ -156,6 +211,7 @@ export function makeCurrencyWalletApi(
156211 return input . props . walletState . name
157212 } ,
158213 async renameWallet ( name : string ) : Promise < void > {
214+ await getStorage ( )
159215 await renameCurrencyWallet ( input , name )
160216 } ,
161217
@@ -164,6 +220,7 @@ export function makeCurrencyWalletApi(
164220 return input . props . walletState . fiat
165221 } ,
166222 async setFiatCurrencyCode ( fiatCurrencyCode : string ) : Promise < void > {
223+ await getStorage ( )
167224 await setCurrencyWalletFiat ( input , fiatCurrencyCode )
168225 } ,
169226
@@ -206,6 +263,7 @@ export function makeCurrencyWalletApi(
206263 if ( input . props . walletState . currencyInfo . hasWalletSettings !== true ) {
207264 throw new Error ( 'Wallet settings unsupported' )
208265 }
266+ await getStorage ( )
209267 await saveWalletSettingsFile ( input , settings )
210268 } ,
211269
@@ -270,6 +328,7 @@ export function makeCurrencyWalletApi(
270328
271329 // Transactions history:
272330 async getNumTransactions ( opts : EdgeTokenIdOptions ) : Promise < number > {
331+ const engine = await getEngine ( )
273332 const upgradedCurrency = upgradeCurrencyCode ( {
274333 allTokens : input . props . state . accounts [ accountId ] . allTokens [ pluginId ] ,
275334 currencyInfo : plugin . currencyInfo ,
@@ -282,6 +341,7 @@ export function makeCurrencyWalletApi(
282341 async $internalStreamTransactions (
283342 opts : EdgeStreamTransactionOptions
284343 ) : Promise < InternalWalletStream > {
344+ const engine = await getEngine ( )
285345 const {
286346 afterDate,
287347 batchSize = 10 ,
@@ -416,6 +476,7 @@ export function makeCurrencyWalletApi(
416476 async getAddresses (
417477 opts : EdgeGetReceiveAddressOptions
418478 ) : Promise < EdgeAddress [ ] > {
479+ const engine = await getEngine ( )
419480 if ( engine . getAddresses != null ) {
420481 return await engine . getAddresses ( opts )
421482 } else {
@@ -515,12 +576,15 @@ export function makeCurrencyWalletApi(
515576
516577 // Sending:
517578 async broadcastTx ( tx : EdgeTransaction ) : Promise < EdgeTransaction > {
579+ const engine = await getEngine ( )
580+
518581 // Only provide wallet info if currency requires it:
519582 const privateKeys = unsafeBroadcastTx ? walletInfo . keys : undefined
520583
521584 return await engine . broadcastTx ( tx , { privateKeys } )
522585 } ,
523586 async getMaxSpendable ( spendInfo : EdgeSpendInfo ) : Promise < string > {
587+ const engine = await getEngine ( )
524588 return await getMaxSpendableInner (
525589 spendInfo ,
526590 plugin ,
@@ -532,6 +596,7 @@ export function makeCurrencyWalletApi(
532596 async getPaymentProtocolInfo (
533597 paymentProtocolUrl : string
534598 ) : Promise < EdgePaymentProtocolInfo > {
599+ const engine = await getEngine ( )
535600 if ( engine . getPaymentProtocolInfo == null ) {
536601 throw new Error (
537602 "'getPaymentProtocolInfo' is not implemented on wallets of this type"
@@ -540,6 +605,7 @@ export function makeCurrencyWalletApi(
540605 return await engine . getPaymentProtocolInfo ( paymentProtocolUrl )
541606 } ,
542607 async makeSpend ( spendInfo : EdgeSpendInfo ) : Promise < EdgeTransaction > {
608+ const engine = await getEngine ( )
543609 spendInfo = upgradeMemos ( spendInfo , plugin . currencyInfo )
544610 const {
545611 assetAction,
@@ -634,6 +700,7 @@ export function makeCurrencyWalletApi(
634700 return tx
635701 } ,
636702 async saveTx ( transaction : EdgeTransaction ) : Promise < void > {
703+ const engine = await getEngine ( )
637704 if ( input . props . walletState . txs [ transaction . txid ] == null ) {
638705 const { fileName, txFile } = await setupNewTxMetadata (
639706 input ,
@@ -653,6 +720,7 @@ export function makeCurrencyWalletApi(
653720 } ,
654721
655722 async saveTxAction ( opts ) : Promise < void > {
723+ await getEngine ( )
656724 const { txid, tokenId, assetAction, savedAction } = opts
657725 await updateCurrencyWalletTxMetadata (
658726 input ,
@@ -666,6 +734,7 @@ export function makeCurrencyWalletApi(
666734 } ,
667735
668736 async saveTxMetadata ( opts : EdgeSaveTxMetadataOptions ) : Promise < void > {
737+ await getEngine ( )
669738 const { txid, tokenId, metadata } = opts
670739
671740 await updateCurrencyWalletTxMetadata (
@@ -681,6 +750,7 @@ export function makeCurrencyWalletApi(
681750 bytes : Uint8Array ,
682751 opts : EdgeSignMessageOptions = { }
683752 ) : Promise < string > {
753+ const engine = await getEngine ( )
684754 const privateKeys = walletInfo . keys
685755
686756 if ( engine . signBytes != null ) {
@@ -706,18 +776,21 @@ export function makeCurrencyWalletApi(
706776 message : string ,
707777 opts : EdgeSignMessageOptions = { }
708778 ) : Promise < string > {
779+ const engine = await getEngine ( )
709780 if ( engine . signMessage == null ) {
710781 throw new Error ( `${ pluginId } doesn't support signing messages` )
711782 }
712783 const privateKeys = walletInfo . keys
713784 return await engine . signMessage ( message , privateKeys , opts )
714785 } ,
715786 async signTx ( tx : EdgeTransaction ) : Promise < EdgeTransaction > {
787+ const engine = await getEngine ( )
716788 const privateKeys = walletInfo . keys
717789
718790 return await engine . signTx ( tx , privateKeys )
719791 } ,
720792 async sweepPrivateKeys ( spendInfo : EdgeSpendInfo ) : Promise < EdgeTransaction > {
793+ const engine = await getEngine ( )
721794 if ( engine . sweepPrivateKeys == null ) {
722795 throw new Error ( 'Sweeping this currency is not supported.' )
723796 }
@@ -726,6 +799,7 @@ export function makeCurrencyWalletApi(
726799
727800 // Accelerating:
728801 async accelerate ( tx : EdgeTransaction ) : Promise < EdgeTransaction | null > {
802+ const engine = await getEngine ( )
729803 if ( engine . accelerate == null ) return null
730804 return await engine . accelerate ( tx )
731805 } ,
@@ -737,9 +811,11 @@ export function makeCurrencyWalletApi(
737811
738812 // Wallet management:
739813 async dumpData ( ) : Promise < EdgeDataDump > {
814+ const engine = await getEngine ( )
740815 return await engine . dumpData ( )
741816 } ,
742817 async resyncBlockchain ( ) : Promise < void > {
818+ const engine = await getEngine ( )
743819 const shortId = input . props . walletId . slice ( 0 , 2 )
744820 input . props . log . warn ( `enabledTokenIds: ${ shortId } resyncBlockchain` )
745821 ai . props . dispatch ( {
@@ -764,6 +840,7 @@ export function makeCurrencyWalletApi(
764840
765841 // URI handling:
766842 async encodeUri ( options : EdgeEncodeUri ) : Promise < string > {
843+ const tools = await getTools ( )
767844 return await tools . encodeUri (
768845 options ,
769846 makeMetaTokens (
@@ -772,6 +849,7 @@ export function makeCurrencyWalletApi(
772849 )
773850 } ,
774851 async parseUri ( uri : string , currencyCode ?: string ) : Promise < EdgeParsedUri > {
852+ const tools = await getTools ( )
775853 const parsedUri = await tools . parseUri (
776854 uri ,
777855 currencyCode ,
@@ -792,7 +870,14 @@ export function makeCurrencyWalletApi(
792870 } ,
793871
794872 // Generic:
795- otherMethods
873+ get otherMethods ( ) : EdgeOtherMethods {
874+ const engine = input . props . walletOutput ?. engine
875+ if ( engine == null ) return emptyOtherMethods
876+ if ( engineOtherMethods == null ) {
877+ engineOtherMethods = makeEngineOtherMethods ( engine )
878+ }
879+ return engineOtherMethods
880+ }
796881 }
797882
798883 return bridgifyObject ( out )
0 commit comments