import isEmpty from 'ramda/src/isEmpty' ; import { ValuesType } from 'utility-types' ; import { NetworkConfig , NETWORKS_CONFIG , SCHEMA_BASE } from '@database/data' ; import { createDefaultValues } from '@database/generateDefaultValues' ; import { DataStore , ExtendedAsset , ExtendedContact , ExtendedContract , ExtendedNotification , ExtendedUserAction , ITxReceipt , LocalStorage , LSKeys , Network , NetworkId , NetworkLegacy , NetworkNodes , NodeType , TUuid } from '@types' ; import { isVoid } from '@utils' ; import { map , mergeRight , pipe } from '@vendor' ; type ObjToArray = < T > ( o : T ) => ValuesType < T > [ ] ; const objToArray = ( obj ) => Object . values ( obj ) ; type ArrayToObj = < K extends string | number > ( k : K ) => < V extends any [ ] > ( arr : V ) => Record < K , ValuesType < V > > ; const arrayToObj = ( key ) => ( arr ) => arr . reduce ( ( acc , curr ) => ( { ... acc , [ curr [ key ] ] : curr } ) , { } ) ; type ObjToExtendedArray = < T > ( o : T ) => unknown [ ] ; export const objToExtendedArray = ( obj ) => Object . entries ( obj ) . reduce ( ( acc , [ uuid , n ] ) => { return acc . concat ( [ { ... n , uuid } ] ) ; } , [ ] as unknown [ ] ) ; export const mergeConfigWithLocalStorage = ( defaultConfig , ls ) : LocalStorage => { const customNetworks = ( Object . fromEntries ( Object . entries ( ls . networks ) . filter ( ( n ) => n [ 1 ] . isCustom ) . map ( ( [ k , v ] ) => [ k , { ... v , tokens : [ ] } ] ) ) as unknown ) as NetworkConfig ; const mergeWithDefault = ( config ) => mergeRight ( config , customNetworks ) ; const lsContracts = objToArray ( ls [ LSKeys . CONTRACTS ] ) as ExtendedContract [ ] ; const lsAssets = objToArray ( ls [ LSKeys . ASSETS ] ) as ExtendedAsset [ ] ; const addCustomContracts = map ( ( n ) => { const contracts = lsContracts . filter ( ( c ) => c . networkId === n . id ) ; return ! isVoid ( contracts ) ? { ... n , contracts : [ ... n . contracts , ... contracts ] } : n ; } ) ; const addCustomAssets = map ( ( n ) => { const assets = lsAssets . filter ( ( c ) => c . networkId === n . id ) ; return ! isVoid ( assets ) ? { ... n , tokens : [ ... n . tokens , ... assets . map ( ( a ) => ( { ... a , address : a . contractAddress } ) ) ] } : n ; } ) ; const config = pipe ( mergeWithDefault , addCustomContracts , addCustomAssets ) ( defaultConfig ) ; if ( ls [ LSKeys . NETWORK_NODES ] ) { Object . entries ( ls [ LSKeys . NETWORK_NODES ] ) . forEach ( ( [ networkId , networkSetup ] ) => { config [ networkId ] . selectedNode = networkSetup . selectedNode ; if ( networkSetup . nodes ) { config [ networkId ] . nodes = networkSetup . nodes . filter ( ( node ) => node . type !== NodeType . WEB3 ) ; } } ) ; } return createDefaultValues ( SCHEMA_BASE , config ) ; } ; export function marshallState ( ls ) { const mergedLs = mergeConfigWithLocalStorage ( NETWORKS_CONFIG , ls ) ; return { version : ls . version , [ LSKeys . ACCOUNTS ] : Object . values ( ls [ LSKeys . ACCOUNTS ] ) , [ LSKeys . ADDRESS_BOOK ] : objToExtendedArray ( ls [ LSKeys . ADDRESS_BOOK ] ) as ExtendedContact [ ] , [ LSKeys . ASSETS ] : objToArray ( mergedLs [ LSKeys . ASSETS ] ) as ExtendedAsset [ ] , [ LSKeys . RATES ] : ls [ LSKeys . RATES ] , [ LSKeys . TRACKED_ASSETS ] : ls [ LSKeys . TRACKED_ASSETS ] , [ LSKeys . CONTRACTS ] : objToArray ( mergedLs [ LSKeys . CONTRACTS ] ) as ExtendedContract [ ] , [ LSKeys . NETWORKS ] : Object . values ( mergedLs [ LSKeys . NETWORKS ] ) , [ LSKeys . NOTIFICATIONS ] : objToExtendedArray ( ls [ LSKeys . NOTIFICATIONS ] ) as ExtendedNotification [ ] , [ LSKeys . SETTINGS ] : ls [ LSKeys . SETTINGS ] , [ LSKeys . USER_ACTIONS ] : ls [ LSKeys . USER_ACTIONS ] ? ( objToExtendedArray ( ls [ LSKeys . USER_ACTIONS ] ) as ExtendedUserAction [ ] ) : [ ] , [ LSKeys . PROMO_POAPS ] : ls [ LSKeys . PROMO_POAPS ] , [ LSKeys . CONNECTIONS ] : ls [ LSKeys . CONNECTIONS ] , [ LSKeys . CLAIMS ] : ls [ LSKeys . CLAIMS ] } ; } export const constructNetworkNodes = ( networks ) => { const networkNodes = { } as LocalStorage [ LSKeys . NETWORK_NODES ] ; networks . forEach ( ( n ) => { const networkSetup = { } ; if ( n . selectedNode !== undefined ) { networkSetup . selectedNode = n . selectedNode ; } const customNodes = n . nodes . filter ( ( node ) => node . isCustom ) ; if ( customNodes . length ) { networkSetup . nodes = customNodes ; } if ( ! isEmpty ( networkSetup ) ) { networkNodes [ n . id ] = networkSetup ; } } ) ; return networkNodes ; } ; export function deMarshallState ( st ) { return { version : st . version , mtime : Date . now ( ) , [ LSKeys . ACCOUNTS ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . ACCOUNTS ] . map ( ( x ) => ( { ... x , transactions : x . transactions . map ( ( tx ) => { const { stage , ... validTx } = tx ; return { ... validTx , status : tx . status || stage } ; } ) , network : undefined } ) ) ) , [ LSKeys . ADDRESS_BOOK ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . ADDRESS_BOOK ] ) , [ LSKeys . ASSETS ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . ASSETS ] . filter ( ( a ) => a . isCustom ) ) , [ LSKeys . RATES ] : st [ LSKeys . RATES ] , [ LSKeys . TRACKED_ASSETS ] : st [ LSKeys . TRACKED_ASSETS ] , [ LSKeys . CONTRACTS ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . CONTRACTS ] . filter ( ( c ) => c . isCustom ) ) , [ LSKeys . NETWORKS ] : st [ LSKeys . NETWORKS ] . filter ( ( c ) => c . isCustom ) . reduce ( ( acc , curr ) => ( { ... acc , [ curr . id ] : { ... curr , nodes : curr . nodes . filter ( ( { type } ) => type !== NodeType . WEB3 ) } } ) , { } as Record < NetworkId , Network > ) , [ LSKeys . NOTIFICATIONS ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . NOTIFICATIONS ] ) , [ LSKeys . SETTINGS ] : st [ LSKeys . SETTINGS ] , [ LSKeys . NETWORK_NODES ] : constructNetworkNodes ( st [ LSKeys . NETWORKS ] ) , [ LSKeys . USER_ACTIONS ] : arrayToObj ( 'uuid' ) ( st [ LSKeys . USER_ACTIONS ] ) , [ LSKeys . PROMO_POAPS ] : st [ LSKeys . PROMO_POAPS ] , [ LSKeys . CONNECTIONS ] : st [ LSKeys . CONNECTIONS ] , [ LSKeys . CLAIMS ] : st [ LSKeys . CLAIMS ] } ; }