@@ -19,9 +19,11 @@ export class AbiRegistry {
1919
2020 private extend ( json : { name : string ; endpoints : any [ ] ; types : any [ ] } ) : AbiRegistry {
2121 json . types = json . types || { } ;
22+
2223 // The "endpoints" collection is interpreted by "ContractInterface".
2324 let iface = ContractInterface . fromJSON ( json ) ;
2425 this . interfaces . push ( iface ) ;
26+
2527 for ( const customTypeName in json . types ) {
2628 let itemJson = json . types [ customTypeName ] ;
2729 let typeDiscriminant = itemJson . type ;
@@ -30,8 +32,12 @@ export class AbiRegistry {
3032 let customType = this . createCustomType ( typeDiscriminant , itemJson ) ;
3133 this . customTypes . push ( customType ) ;
3234 }
35+
36+ this . sortCustomTypesByDependencies ( ) ;
37+
3338 return this ;
3439 }
40+
3541 private createCustomType ( typeDiscriminant : string , json : any ) : CustomType {
3642 if ( typeDiscriminant == "struct" ) {
3743 return StructType . fromJSON ( json ) ;
@@ -41,30 +47,50 @@ export class AbiRegistry {
4147 }
4248 throw new errors . ErrTypingSystem ( `Unknown type discriminant: ${ typeDiscriminant } ` ) ;
4349 }
50+
51+ private sortCustomTypesByDependencies ( ) {
52+ this . customTypes . sort ( ( a : CustomType , b : CustomType ) => {
53+ const bDependsonA = b . getNamesOfDependencies ( ) . indexOf ( a . getName ( ) ) > - 1 ;
54+ if ( bDependsonA ) {
55+ // Sort "a" before "b".
56+ return - 1 ;
57+ }
58+
59+ // Keep original order.
60+ return 0 ;
61+ } ) ;
62+ }
63+
4464 getInterface ( name : string ) : ContractInterface {
4565 let result = this . interfaces . find ( ( e ) => e . name == name ) ;
4666 guardValueIsSetWithMessage ( `interface [${ name } ] not found` , result ) ;
4767 return result ! ;
4868 }
69+
4970 getInterfaces ( names : string [ ] ) : ContractInterface [ ] {
5071 return names . map ( ( name ) => this . getInterface ( name ) ) ;
5172 }
73+
5274 getStruct ( name : string ) : StructType {
5375 let result = this . customTypes . find ( ( e ) => e . getName ( ) == name && e . hasExactClass ( StructType . ClassName ) ) ;
5476 guardValueIsSetWithMessage ( `struct [${ name } ] not found` , result ) ;
5577 return < StructType > result ! ;
5678 }
79+
5780 getStructs ( names : string [ ] ) : StructType [ ] {
5881 return names . map ( ( name ) => this . getStruct ( name ) ) ;
5982 }
83+
6084 getEnum ( name : string ) : EnumType {
6185 let result = this . customTypes . find ( ( e ) => e . getName ( ) == name && e . hasExactClass ( EnumType . ClassName ) ) ;
6286 guardValueIsSetWithMessage ( `enum [${ name } ] not found` , result ) ;
6387 return < EnumType > result ! ;
6488 }
89+
6590 getEnums ( names : string [ ] ) : EnumType [ ] {
6691 return names . map ( ( name ) => this . getEnum ( name ) ) ;
6792 }
93+
6894 /**
6995 * Right after loading ABI definitions into a registry, the endpoints and the custom types (structs, enums)
7096 * use raw types for their I/O parameters (in the case of endpoints), or for their fields (in the case of structs).
@@ -79,11 +105,13 @@ export class AbiRegistry {
79105 let mapper = new TypeMapper ( [ ] ) ;
80106 let newCustomTypes : CustomType [ ] = [ ] ;
81107 let newInterfaces : ContractInterface [ ] = [ ] ;
108+
82109 // First, remap custom types (actually, under the hood, this will remap types of struct fields)
83110 for ( const type of this . customTypes ) {
84111 const mappedTyped = mapper . mapType ( type ) ;
85112 newCustomTypes . push ( mappedTyped ) ;
86113 }
114+
87115 // Then, remap types of all endpoint parameters.
88116 // But we'll use an enhanced mapper, that takes into account the results from the previous step.
89117 mapper = new TypeMapper ( newCustomTypes ) ;
@@ -95,6 +123,7 @@ export class AbiRegistry {
95123 let newConstructor = iface . constructorDefinition ? mapEndpoint ( iface . constructorDefinition , mapper ) : null ;
96124 newInterfaces . push ( new ContractInterface ( iface . name , newConstructor , newEndpoints ) ) ;
97125 }
126+
98127 // Now return the new registry, with all types remapped to known types
99128 let newRegistry = new AbiRegistry ( ) ;
100129 newRegistry . customTypes . push ( ...newCustomTypes ) ;
0 commit comments