@@ -10,13 +10,14 @@ import { TransformerTools } from '../transform';
10
10
import { extractNatspec } from '../utils/extractNatspec' ;
11
11
import { decodeTypeIdentifier } from '../utils/type-id' ;
12
12
import { parseTypeId } from '../utils/parse-type-id' ;
13
+ import { ASTResolver } from '../ast-resolver' ;
13
14
14
15
// By default, make the contract a total of 50 slots (storage + gap)
15
16
const DEFAULT_SLOT_COUNT = 50 ;
16
17
17
18
export function * addStorageGaps (
18
19
sourceUnit : SourceUnit ,
19
- { getLayout } : TransformerTools ,
20
+ { getLayout, resolver } : TransformerTools ,
20
21
) : Generator < Transformation > {
21
22
for ( const contract of findAll ( 'ContractDefinition' , sourceUnit ) ) {
22
23
if ( contract . contractKind === 'contract' ) {
@@ -27,7 +28,7 @@ export function* addStorageGaps(
27
28
}
28
29
}
29
30
30
- const gapSize = targetSlots - getContractSlotCount ( contract , getLayout ( contract ) ) ;
31
+ const gapSize = targetSlots - getContractSlotCount ( contract , getLayout ( contract ) , resolver ) ;
31
32
32
33
if ( gapSize <= 0 ) {
33
34
throw new Error (
@@ -71,8 +72,9 @@ function isStorageVariable(varDecl: VariableDeclaration): boolean {
71
72
}
72
73
}
73
74
74
- function getNumberOfBytesOfValueType ( typeId : string ) : number {
75
- const details = parseTypeId ( typeId ) . head . match ( / ^ t _ (?< base > [ a - z ] + ) (?< size > \d + ) ? / ) ;
75
+ function getNumberOfBytesOfValueType ( typeId : string , resolver : ASTResolver ) : number {
76
+ const { head, tail } = parseTypeId ( typeId ) ;
77
+ const details = head . match ( / ^ t _ (?< base > [ a - z A - Z ] + ) (?< size > \d + ) ? / ) ;
76
78
switch ( details ?. groups ?. base ) {
77
79
case 'bool' :
78
80
case 'byte' :
@@ -86,12 +88,20 @@ function getNumberOfBytesOfValueType(typeId: string): number {
86
88
case 'int' :
87
89
case 'uint' :
88
90
return parseInt ( details . groups . size , 10 ) / 8 ;
91
+ case 'userDefinedValueType' :
92
+ const definition = resolver . resolveNode ( 'UserDefinedValueTypeDefinition' , Number ( tail ) ) ;
93
+ const underlying = definition . underlyingType . typeDescriptions . typeIdentifier ;
94
+ if ( underlying ) {
95
+ return getNumberOfBytesOfValueType ( underlying , resolver ) ;
96
+ } else {
97
+ throw new Error ( `Unsupported value type: ${ typeId } ` ) ;
98
+ }
89
99
default :
90
100
throw new Error ( `Unsupported value type: ${ typeId } ` ) ;
91
101
}
92
102
}
93
103
94
- function getContractSlotCount ( contractNode : ContractDefinition , layout : StorageLayout ) : number {
104
+ function getContractSlotCount ( contractNode : ContractDefinition , layout : StorageLayout , resolver : ASTResolver ) : number {
95
105
// This tracks both slot and offset:
96
106
// - slot = Math.floor(contractSizeInBytes / 32)
97
107
// - offset = contractSizeInBytes % 32
@@ -109,7 +119,7 @@ function getContractSlotCount(contractNode: ContractDefinition, layout: StorageL
109
119
const size =
110
120
layout . types && layout . types [ typeIdentifier ]
111
121
? parseInt ( layout . types [ typeIdentifier ] ?. numberOfBytes ?? '' )
112
- : getNumberOfBytesOfValueType ( typeIdentifier ) ;
122
+ : getNumberOfBytesOfValueType ( typeIdentifier , resolver ) ;
113
123
114
124
// used space in the current slot
115
125
const offset = contractSizeInBytes % 32 ;
0 commit comments