import { Manifest } from './manifest' ; import { isCurrentLayoutVersion } from './storage/extract' ; import { StorageLayout , isStructMembers } from './storage/layout' ; import { ValidationData } from './validate/data' ; import { findVersionWithoutMetadataMatches , unfoldStorageLayout } from './validate/query' ; import { stabilizeTypeIdentifier } from './utils/type-id' ; import { DeepArray , deepEqual } from './utils/deep-array' ; export async function getStorageLayoutForAddress ( manifest , validations , implAddress ) { const data = await manifest . read ( ) ; const versionWithoutMetadata = Object . keys ( data . impls ) . find ( v => data . impls [ v ] ?. address === implAddress ) ; if ( versionWithoutMetadata === undefined ) { throw new Error ( `Deployment at address ${ implAddress } is not registered` ) ; } const { layout } = data . impls [ versionWithoutMetadata ] ! ; if ( isCurrentLayoutVersion ( layout ) ) { return layout ; } else { const updatedLayout = getUpdatedStorageLayout ( validations , versionWithoutMetadata , layout ) ; if ( updatedLayout === undefined ) { return layout ; } else { await manifest . lockedRun ( async ( ) => { const data = await manifest . read ( ) ; data . impls [ versionWithoutMetadata ] ! . layout = updatedLayout ; await manifest . write ( data ) ; } ) ; return updatedLayout ; } } } export function getUpdatedStorageLayout ( data , versionWithoutMetadata , layout ) { const sameLayout = new Map < string , StorageLayout > ( ) ; outer : for ( const [ contractName , validationRun ] of findVersionWithoutMetadataMatches ( data , versionWithoutMetadata ) ) { const updatedLayout = unfoldStorageLayout ( validationRun , contractName ) ; if ( updatedLayout . storage . length !== layout . storage . length ) { continue ; } for ( const [ i , item ] of layout . storage . entries ( ) ) { const updatedItem = updatedLayout . storage [ i ] ; if ( item . label !== updatedItem . label ) { continue outer ; } if ( stabilizeTypeIdentifier ( item . type ) !== stabilizeTypeIdentifier ( updatedItem . type ) ) { continue outer ; } } const { version } = validationRun [ contractName ] ; if ( version && ! sameLayout . has ( version . withMetadata ) ) { sameLayout . set ( version . withMetadata , updatedLayout ) ; } } if ( sameLayout . size > 1 ) { const typeMembers = new Map < string , DeepArray < string > > ( ) ; for ( const { types } of sameLayout . values ( ) ) { for ( const [ typeId , item ] of Object . entries ( types ) ) { if ( item . members === undefined ) { continue ; } const members = isStructMembers ( item . members ) ? item . members . map ( m => [ stabilizeTypeIdentifier ( m . type ) , m . label ] ) : item . members ; const stableId = stabilizeTypeIdentifier ( typeId ) ; if ( ! typeMembers . has ( stableId ) ) { typeMembers . set ( stableId , members ) ; } else if ( ! deepEqual ( members , typeMembers . get ( stableId ) ) ) { return undefined ; } } } } if ( sameLayout . size > 0 ) { const [ updatedLayout ] = sameLayout . values ( ) ; return updatedLayout ; } }