import _test , { TestInterface } from 'ava' ; import { artifacts } from 'hardhat' ; import { validate , getStorageLayout , getContractVersion , assertUpgradeSafe , ValidationOptions , RunValidation , } from './validate' ; import { solcInputOutputDecoder } from './src-decoder' ; interface Context { validation : RunValidation ; } const test = _test as TestInterface < Context > ; test . before ( async ( t ) => { const contracts = [ 'contracts/test/Validations.sol:HasEmptyConstructor' , 'contracts/test/ValidationsNatspec.sol:HasNonEmptyConstructorNatspec1' , 'contracts/test/Proxiable.sol:ChildOfProxiable' , ] ; t . context . validation = { } as RunValidation ; for ( const contract of contracts ) { const buildInfo = await artifacts . getBuildInfo ( contract ) ; if ( buildInfo === undefined ) { throw new Error ( `Build info not found for contract ${ contract }` ) ; } const solcOutput = buildInfo . output ; const solcInput = buildInfo . input ; const decodeSrc = solcInputOutputDecoder ( solcInput , solcOutput ) ; Object . assign ( t . context . validation , validate ( solcOutput , decodeSrc ) ) ; } } ) ; function testValid ( name , kind , valid ) { testOverride ( name , kind , { } , valid ) ; } function testOverride ( name , kind , opts , valid ) { const optKeys = Object . keys ( opts ) ; const describeOpts = optKeys . length > 0 ? '(' + optKeys . join ( ', ' ) + ')' : '' ; const testName = [ valid ? 'accepts' : 'rejects' , kind , name , describeOpts ] . join ( ' ' ) ; test ( testName , t => { const version = getContractVersion ( t . context . validation , name ) ; const assertUpgSafe = ( ) => assertUpgradeSafe ( [ t . context . validation ] , version , { kind , ... opts } ) ; if ( valid ) { t . notThrows ( assertUpgSafe ) ; } else { t . throws ( assertUpgSafe ) ; } } ) ; } testValid ( 'HasEmptyConstructor' , 'transparent' , true ) ; testValid ( 'HasConstantStateVariableAssignment' , 'transparent' , true ) ; testValid ( 'HasStateVariable' , 'transparent' , true ) ; testValid ( 'UsesImplicitSafeInternalLibrary' , 'transparent' , true ) ; testValid ( 'UsesExplicitSafeInternalLibrary' , 'transparent' , true ) ; testValid ( 'HasNonEmptyConstructor' , 'transparent' , false ) ; testValid ( 'ParentHasNonEmptyConstructor' , 'transparent' , false ) ; testValid ( 'AncestorHasNonEmptyConstructor' , 'transparent' , false ) ; testValid ( 'HasStateVariableAssignment' , 'transparent' , false ) ; testValid ( 'HasImmutableStateVariable' , 'transparent' , false ) ; testValid ( 'HasSelfDestruct' , 'transparent' , false ) ; testValid ( 'HasDelegateCall' , 'transparent' , false ) ; testValid ( 'ImportedParentHasStateVariableAssignment' , 'transparent' , false ) ; testValid ( 'UsesImplicitUnsafeInternalLibrary' , 'transparent' , false ) ; testValid ( 'UsesExplicitUnsafeInternalLibrary' , 'transparent' , false ) ; testValid ( 'UsesImplicitUnsafeExternalLibrary' , 'transparent' , false ) ; testValid ( 'UsesExplicitUnsafeExternalLibrary' , 'transparent' , false ) ; testValid ( 'UsesImplicitSafeExternalLibrary' , 'transparent' , false ) ; testValid ( 'UsesExplicitSafeExternalLibrary' , 'transparent' , false ) ; test ( 'inherited storage' , t => { const version = getContractVersion ( t . context . validation , 'StorageInheritChild' ) ; const layout = getStorageLayout ( [ t . context . validation ] , version ) ; t . is ( layout . storage . length , 8 ) ; for ( let i = 0 ; i < layout . storage . length ; i ++ ) { t . is ( layout . storage [ i ] . label , `v${ i }` ) ; t . truthy ( layout . types [ layout . storage [ i ] . type ] ) ; } } ) ; testOverride ( 'UsesImplicitSafeExternalLibrary' , 'transparent' , { unsafeAllowLinkedLibraries : true } , true ) ; testOverride ( 'UsesExplicitSafeExternalLibrary' , 'transparent' , { unsafeAllowLinkedLibraries : true } , true ) ; testOverride ( 'UsesImplicitSafeExternalLibrary' , 'transparent' , { unsafeAllow : [ 'external-library-linking' ] } , true ) ; testOverride ( 'UsesExplicitSafeExternalLibrary' , 'transparent' , { unsafeAllow : [ 'external-library-linking' ] } , true ) ; testValid ( 'HasEmptyConstructor' , 'uups' , false ) ; testValid ( 'HasInternalUpgradeToFunction' , 'uups' , false ) ; testValid ( 'HasUpgradeToFunction' , 'uups' , true ) ; testValid ( 'ParentHasUpgradeToFunction' , 'uups' , true ) ; testValid ( 'ChildOfProxiable' , 'uups' , true ) ; testValid ( 'HasNonEmptyConstructorNatspec1' , 'transparent' , true ) ; testValid ( 'HasNonEmptyConstructorNatspec2' , 'transparent' , true ) ; testValid ( 'HasNonEmptyConstructorNatspec3' , 'transparent' , true ) ; testValid ( 'HasNonEmptyConstructorNatspec4' , 'transparent' , true ) ; testValid ( 'ParentHasNonEmptyConstructorNatspec1' , 'transparent' , true ) ; testValid ( 'ParentHasNonEmptyConstructorNatspec2' , 'transparent' , true ) ; testValid ( 'AncestorHasNonEmptyConstructorNatspec1' , 'transparent' , true ) ; testValid ( 'AncestorHasNonEmptyConstructorNatspec2' , 'transparent' , true ) ; testValid ( 'HasStateVariableAssignmentNatspec1' , 'transparent' , true ) ; testValid ( 'HasStateVariableAssignmentNatspec2' , 'transparent' , true ) ; testValid ( 'HasStateVariableAssignmentNatspec3' , 'transparent' , false ) ; testValid ( 'HasImmutableStateVariableNatspec1' , 'transparent' , true ) ; testValid ( 'HasImmutableStateVariableNatspec2' , 'transparent' , true ) ; testValid ( 'HasImmutableStateVariableNatspec3' , 'transparent' , false ) ; testValid ( 'HasSelfDestructNatspec1' , 'transparent' , true ) ; testValid ( 'HasSelfDestructNatspec2' , 'transparent' , true ) ; testValid ( 'HasSelfDestructNatspec3' , 'transparent' , true ) ; testValid ( 'HasDelegateCallNatspec1' , 'transparent' , true ) ; testValid ( 'HasDelegateCallNatspec2' , 'transparent' , true ) ; testValid ( 'HasDelegateCallNatspec3' , 'transparent' , true ) ; testValid ( 'ImportedParentHasStateVariableAssignmentNatspec1' , 'transparent' , true ) ; testValid ( 'ImportedParentHasStateVariableAssignmentNatspec2' , 'transparent' , true ) ; testValid ( 'UsesImplicitSafeInternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesImplicitSafeExternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesImplicitUnsafeInternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesImplicitUnsafeExternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesExplicitSafeInternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesExplicitSafeExternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesExplicitUnsafeInternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'UsesExplicitUnsafeExternalLibraryNatspec' , 'transparent' , true ) ; testValid ( 'TransitiveLibraryIsUnsafe' , 'transparent' , false ) ;