@@ -29,6 +29,7 @@ import {
2929 getNetworkName ,
3030 isRailgunSupported ,
3131} from './types' ;
32+ import leveljs from 'level-js' ;
3233
3334// Engine singleton state
3435let engineState : EngineState = {
@@ -173,32 +174,112 @@ const RPC_PROVIDERS: Record<RailgunChainId, FallbackProviderJsonConfig> = {
173174 } ,
174175} ;
175176
177+ /**
178+ * IndexedDB database name for artifact caching
179+ */
180+ const ARTIFACT_DB_NAME = 'railgun-artifacts' ;
181+ const ARTIFACT_STORE_NAME = 'artifacts' ;
182+
183+ /**
184+ * Open IndexedDB for artifact storage
185+ */
186+ function openArtifactDB ( ) : Promise < IDBDatabase > {
187+ return new Promise ( ( resolve , reject ) => {
188+ const request = indexedDB . open ( ARTIFACT_DB_NAME , 1 ) ;
189+
190+ request . onerror = ( ) => {
191+ console . error ( '[RAILGUN] Failed to open artifact database:' , request . error ) ;
192+ reject ( request . error ) ;
193+ } ;
194+
195+ request . onsuccess = ( ) => {
196+ resolve ( request . result ) ;
197+ } ;
198+
199+ request . onupgradeneeded = ( event ) => {
200+ const db = ( event . target as IDBOpenDBRequest ) . result ;
201+ if ( ! db . objectStoreNames . contains ( ARTIFACT_STORE_NAME ) ) {
202+ db . createObjectStore ( ARTIFACT_STORE_NAME ) ;
203+ }
204+ } ;
205+ } ) ;
206+ }
207+
176208/**
177209 * Artifact store configuration for browser environment
178- * Uses a CDN-based approach for downloading ZK circuit artifacts
210+ * Uses IndexedDB for caching ZK circuit artifacts
179211 */
180212const artifactStore = {
181- get : async ( _path : string ) : Promise < string | Buffer | null > => {
182- // In browser, return null to trigger download from CDN
183- return null ;
213+ get : async ( path : string ) : Promise < string | Buffer | null > => {
214+ try {
215+ const db = await openArtifactDB ( ) ;
216+ return new Promise ( ( resolve ) => {
217+ const transaction = db . transaction ( ARTIFACT_STORE_NAME , 'readonly' ) ;
218+ const store = transaction . objectStore ( ARTIFACT_STORE_NAME ) ;
219+ const request = store . get ( path ) ;
220+
221+ request . onerror = ( ) => {
222+ console . warn ( '[RAILGUN] Failed to get artifact:' , path ) ;
223+ resolve ( null ) ;
224+ } ;
225+
226+ request . onsuccess = ( ) => {
227+ resolve ( request . result || null ) ;
228+ } ;
229+
230+ transaction . oncomplete = ( ) => {
231+ db . close ( ) ;
232+ } ;
233+ } ) ;
234+ } catch ( error ) {
235+ console . warn ( '[RAILGUN] Artifact store get error:' , error ) ;
236+ return null ;
237+ }
184238 } ,
185- store : async ( _dir : string , _path : string , _item : string | Uint8Array ) : Promise < void > => {
186- // Browser storage is handled internally by the SDK using IndexedDB
239+
240+ store : async ( _dir : string , path : string , item : string | Uint8Array ) : Promise < void > => {
241+ try {
242+ const db = await openArtifactDB ( ) ;
243+ return new Promise ( ( resolve , reject ) => {
244+ const transaction = db . transaction ( ARTIFACT_STORE_NAME , 'readwrite' ) ;
245+ const store = transaction . objectStore ( ARTIFACT_STORE_NAME ) ;
246+ const request = store . put ( item , path ) ;
247+
248+ request . onerror = ( ) => {
249+ console . warn ( '[RAILGUN] Failed to store artifact:' , path ) ;
250+ reject ( request . error ) ;
251+ } ;
252+
253+ request . onsuccess = ( ) => {
254+ resolve ( ) ;
255+ } ;
256+
257+ transaction . oncomplete = ( ) => {
258+ db . close ( ) ;
259+ } ;
260+ } ) ;
261+ } catch ( error ) {
262+ console . warn ( '[RAILGUN] Artifact store put error:' , error ) ;
263+ }
187264 } ,
188- exists : async ( _path : string ) : Promise < boolean > => {
189- // Let the SDK handle artifact caching
190- return false ;
265+
266+ exists : async ( path : string ) : Promise < boolean > => {
267+ try {
268+ const result = await artifactStore . get ( path ) ;
269+ return result !== null ;
270+ } catch {
271+ return false ;
272+ }
191273 } ,
192274} ;
193275
194276/**
195277 * Create the database storage for browser environment
196- * Uses IndexedDB via localForage internally
278+ * Uses level-js which is abstract-leveldown compatible and backed by IndexedDB
197279 */
198- function createBrowserDatabase ( _dbPath : string ) {
199- // The SDK handles browser database creation internally
200- // This is a no-op for browser environments
201- return undefined ;
280+ function createBrowserDatabase ( dbPath : string ) : ReturnType < typeof leveljs > {
281+ // Create a level-js database (abstract-leveldown compatible, backed by IndexedDB)
282+ return leveljs ( dbPath ) ;
202283}
203284
204285/**
@@ -226,24 +307,47 @@ async function doInitializeEngine(
226307 config ?: Partial < RailgunEngineConfig >
227308) : Promise < boolean > {
228309 try {
310+ console . log ( '[RAILGUN] Starting engine initialization...' ) ;
311+
229312 updateEngineState ( {
230313 status : 'initializing' ,
231314 error : undefined ,
232315 } ) ;
233316
234- const walletSource = config ?. walletSource ?? 'liquyn-swap ' ;
317+ const walletSource = config ?. walletSource ?? 'liquynswap ' ;
235318 const poiNodeURLs = config ?. poiConfig ?. nodeURLs ?? DEFAULT_POI_NODES ;
236- const shouldDebug = config ?. shouldDebug ?? false ;
319+ const shouldDebug = config ?. shouldDebug ?? true ; // Enable debug by default for troubleshooting
320+
321+ console . log ( '[RAILGUN] Config:' , { walletSource, poiNodeURLs, shouldDebug } ) ;
322+
323+ updateEngineState ( { status : 'downloading_artifacts' } ) ;
324+ console . log ( '[RAILGUN] Calling startRailgunEngine...' ) ;
237325
238- // Set up balance update callback
326+ const dbPath = createBrowserDatabase ( 'railgun-db' ) ;
327+ console . log ( '[RAILGUN] Database path:' , dbPath ) ;
328+
329+ // Initialize the engine FIRST - callbacks must be set AFTER engine is started
330+ await startRailgunEngine (
331+ walletSource ,
332+ dbPath ,
333+ shouldDebug ,
334+ artifactStore ,
335+ false , // useNativeArtifacts - false for browser
336+ false , // skipMerkletreeScans - we want full scanning
337+ poiNodeURLs ,
338+ ) ;
339+
340+ console . log ( '[RAILGUN] Engine started, setting up callbacks...' ) ;
341+
342+ // Set up balance update callback AFTER engine is started
239343 setOnBalanceUpdateCallback ( async ( balanceData ) => {
240344 // Balance updated - this will be handled by the wallet module
241345 if ( shouldDebug && isDefined ( balanceData ) ) {
242346 console . log ( '[RAILGUN] Balance update received' ) ;
243347 }
244348 } ) ;
245349
246- // Set up merkletree scan callbacks
350+ // Set up merkletree scan callbacks AFTER engine is started
247351 setOnUTXOMerkletreeScanCallback ( ( scanData ) => {
248352 if ( shouldDebug && isDefined ( scanData ) ) {
249353 const progress = scanData . progress ?? 0 ;
@@ -258,18 +362,7 @@ async function doInitializeEngine(
258362 }
259363 } ) ;
260364
261- updateEngineState ( { status : 'downloading_artifacts' } ) ;
262-
263- // Initialize the engine
264- await startRailgunEngine (
265- walletSource ,
266- createBrowserDatabase ( 'railgun-db' ) ,
267- shouldDebug ,
268- artifactStore ,
269- false , // useNativeArtifacts - false for browser
270- false , // skipMerkletreeScans - we want full scanning
271- poiNodeURLs ,
272- ) ;
365+ console . log ( '[RAILGUN] Callbacks set, loading providers...' ) ;
273366
274367 // Load providers for all supported networks
275368 await loadProvidersForNetworks ( ) ;
@@ -279,8 +372,24 @@ async function doInitializeEngine(
279372
280373 return true ;
281374 } catch ( error ) {
282- const errorMessage = error instanceof Error ? error . message : 'Unknown error' ;
283- console . error ( '[RAILGUN] Engine initialization failed:' , errorMessage ) ;
375+ // Log the full error for debugging
376+ console . error ( '[RAILGUN] Engine initialization failed:' , error ) ;
377+
378+ // Extract error message
379+ let errorMessage = 'Unknown error during engine initialization' ;
380+ if ( error instanceof Error ) {
381+ errorMessage = error . message ;
382+ // Log stack trace for debugging
383+ if ( error . stack ) {
384+ console . error ( '[RAILGUN] Stack trace:' , error . stack ) ;
385+ }
386+ } else if ( typeof error === 'string' ) {
387+ errorMessage = error ;
388+ } else if ( error && typeof error === 'object' ) {
389+ errorMessage = JSON . stringify ( error ) ;
390+ }
391+
392+ console . error ( '[RAILGUN] Error message:' , errorMessage ) ;
284393
285394 updateEngineState ( {
286395 status : 'error' ,
0 commit comments