@@ -10,6 +10,7 @@ use starknet::core::types::contract::{AbiEntry, AbiEvent, TypedAbiEvent, Untyped
1010use starknet:: core:: types:: Felt ;
1111
1212use super :: { ResourceDiff , WorldDiff } ;
13+ use crate :: config:: migration_config:: ManifestAbiFormat ;
1314use crate :: local:: { ExternalContractLocal , ResourceLocal } ;
1415use crate :: remote:: ResourceRemote ;
1516use crate :: ResourceType ;
@@ -27,7 +28,9 @@ pub struct Manifest {
2728 /// vector. When serialized, the entries are always sorted alphabetically by name.
2829 #[ serde(
2930 serialize_with = "serialize_abis_hashmap" ,
30- deserialize_with = "deserialize_abis_hashmap"
31+ deserialize_with = "deserialize_abis_hashmap" ,
32+ default ,
33+ skip_serializing_if = "HashMap::is_empty"
3134 ) ]
3235 pub abis : HashMap < String , AbiEntry > ,
3336}
@@ -47,8 +50,8 @@ pub struct WorldContract {
4750 pub name : String ,
4851 /// Entrypoints of the world.
4952 pub entrypoints : Vec < String > ,
50- /// Abi of the world, skipped during serialization in favor of the `abis` field .
51- #[ serde( skip ) ]
53+ /// Abi of the world. Cleared when we omit inline ABIs from the manifest .
54+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
5255 pub abi : Vec < AbiEntry > ,
5356}
5457
@@ -61,8 +64,8 @@ pub struct DojoContract {
6164 /// Class hash of the contract.
6265 #[ serde_as( as = "UfeHex" ) ]
6366 pub class_hash : Felt ,
64- /// ABI of the contract, skipped during serialization in favor of the `abis` field .
65- #[ serde( skip ) ]
67+ /// ABI of the contract. Cleared when we omit inline ABIs from the manifest .
68+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
6669 pub abi : Vec < AbiEntry > ,
6770 /// Initialization call data.
6871 #[ serde( default ) ]
@@ -82,8 +85,8 @@ pub struct DojoLibrary {
8285 /// Class hash of the contract.
8386 #[ serde_as( as = "UfeHex" ) ]
8487 pub class_hash : Felt ,
85- /// ABI of the contract, skipped during serialization in favor of the `abis` field .
86- #[ serde( skip ) ]
88+ /// ABI of the contract. Cleared when we omit inline ABIs from the manifest .
89+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
8790 pub abi : Vec < AbiEntry > ,
8891 /// Tag of the contract.
8992 pub tag : String ,
@@ -109,8 +112,8 @@ pub struct DojoModel {
109112 /// Selector of the model.
110113 #[ serde_as( as = "UfeHex" ) ]
111114 pub selector : Felt ,
112- /// ABI of the model, skipped during serialization in favor of the `abis` field .
113- #[ serde( skip ) ]
115+ /// ABI of the model. Cleared when we omit inline ABIs from the manifest .
116+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
114117 pub abi : Vec < AbiEntry > ,
115118}
116119
@@ -138,8 +141,8 @@ pub struct DojoEvent {
138141 /// Selector of the event.
139142 #[ serde_as( as = "UfeHex" ) ]
140143 pub selector : Felt ,
141- /// ABI of the event, skipped during serialization in favor of the `abis` field .
142- #[ serde( skip ) ]
144+ /// ABI of the event. Cleared when we omit inline ABIs from the manifest .
145+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
143146 pub abi : Vec < AbiEntry > ,
144147}
145148
@@ -166,9 +169,8 @@ pub struct ExternalContract {
166169 /// Contract address
167170 #[ serde_as( as = "UfeHex" ) ]
168171 pub address : Felt ,
169- /// ABI of the contract.
170- /// Ignored during serialization in favor of the `abis` field.
171- #[ serde( skip) ]
172+ /// ABI of the contract. Cleared when we omit inline ABIs from the manifest.
173+ #[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
172174 pub abi : Vec < AbiEntry > ,
173175 /// Human-readeable constructor call data.
174176 #[ serde( default ) ]
@@ -251,6 +253,24 @@ impl Manifest {
251253 Self { world, contracts, models, events, libraries, external_contracts, abis }
252254 }
253255
256+ /// Removes inline ABI definitions so they are omitted during serialization.
257+ pub fn strip_inline_abis ( & mut self ) {
258+ self . world . abi . clear ( ) ;
259+ self . contracts . iter_mut ( ) . for_each ( |c| c. abi . clear ( ) ) ;
260+ self . models . iter_mut ( ) . for_each ( |m| m. abi . clear ( ) ) ;
261+ self . events . iter_mut ( ) . for_each ( |e| e. abi . clear ( ) ) ;
262+ self . libraries . iter_mut ( ) . for_each ( |l| l. abi . clear ( ) ) ;
263+ self . external_contracts . iter_mut ( ) . for_each ( |c| c. abi . clear ( ) ) ;
264+ }
265+
266+ /// Applies the ABI layout requested for the manifest output.
267+ pub fn apply_abi_format ( & mut self , format : ManifestAbiFormat ) {
268+ match format {
269+ ManifestAbiFormat :: AllInOne => self . strip_inline_abis ( ) ,
270+ ManifestAbiFormat :: PerContract => self . abis . clear ( ) ,
271+ }
272+ }
273+
254274 pub fn get_contract_address ( & self , tag : & str ) -> Option < Felt > {
255275 self . contracts . iter ( ) . find_map ( |c| if c. tag == tag { Some ( c. address ) } else { None } )
256276 }
@@ -522,3 +542,71 @@ fn add_abi_entries(abis: &mut HashMap<String, AbiEntry>, abi: Vec<AbiEntry>) {
522542 abis. insert ( entry_name, abi_entry) ;
523543 }
524544}
545+
546+ #[ cfg( test) ]
547+ mod tests {
548+ use serde_json:: json;
549+ use starknet:: macros:: felt;
550+
551+ use super :: * ;
552+
553+ #[ test]
554+ fn apply_abi_format_controls_serialization ( ) {
555+ let abi_entry: AbiEntry = serde_json:: from_value ( json ! ( {
556+ "type" : "function" ,
557+ "name" : "foo" ,
558+ "inputs" : [ ] ,
559+ "outputs" : [ ] ,
560+ "state_mutability" : "view"
561+ } ) )
562+ . unwrap ( ) ;
563+
564+ let mut manifest_base = Manifest {
565+ world : WorldContract {
566+ class_hash : felt ! ( "0x1" ) ,
567+ address : felt ! ( "0x2" ) ,
568+ seed : "seed" . to_string ( ) ,
569+ name : "world" . to_string ( ) ,
570+ entrypoints : vec ! [ "execute" . to_string( ) ] ,
571+ abi : vec ! [ abi_entry. clone( ) ] ,
572+ } ,
573+ contracts : vec ! [ DojoContract {
574+ address: felt!( "0x3" ) ,
575+ class_hash: felt!( "0x4" ) ,
576+ abi: vec![ abi_entry. clone( ) ] ,
577+ init_calldata: vec![ ] ,
578+ tag: "ns-contract" . to_string( ) ,
579+ systems: vec![ "system" . to_string( ) ] ,
580+ selector: felt!( "0x5" ) ,
581+ } ] ,
582+ libraries : vec ! [ ] ,
583+ models : vec ! [ ] ,
584+ events : vec ! [ ] ,
585+ external_contracts : vec ! [ ] ,
586+ abis : HashMap :: new ( ) ,
587+ } ;
588+
589+ manifest_base. abis . insert ( "foo" . to_string ( ) , abi_entry. clone ( ) ) ;
590+
591+ let default_json = serde_json:: to_value ( & manifest_base) . unwrap ( ) ;
592+ assert ! ( default_json[ "contracts" ] [ 0 ] . get( "abi" ) . is_some( ) ) ;
593+ assert ! ( default_json[ "world" ] . get( "abi" ) . is_some( ) ) ;
594+ assert ! ( default_json. get( "abis" ) . is_some( ) ) ;
595+
596+ let mut all_in_one = manifest_base. clone ( ) ;
597+ all_in_one. apply_abi_format ( ManifestAbiFormat :: AllInOne ) ;
598+
599+ let all_in_one_json = serde_json:: to_value ( & all_in_one) . unwrap ( ) ;
600+ assert ! ( all_in_one_json[ "contracts" ] [ 0 ] . get( "abi" ) . is_none( ) ) ;
601+ assert ! ( all_in_one_json[ "world" ] . get( "abi" ) . is_none( ) ) ;
602+ assert ! ( all_in_one_json. get( "abis" ) . is_some( ) ) ;
603+
604+ let mut per_contract = manifest_base;
605+ per_contract. apply_abi_format ( ManifestAbiFormat :: PerContract ) ;
606+
607+ let per_contract_json = serde_json:: to_value ( & per_contract) . unwrap ( ) ;
608+ assert ! ( per_contract_json[ "contracts" ] [ 0 ] . get( "abi" ) . is_some( ) ) ;
609+ assert ! ( per_contract_json[ "world" ] . get( "abi" ) . is_some( ) ) ;
610+ assert ! ( per_contract_json. get( "abis" ) . is_none( ) ) ;
611+ }
612+ }
0 commit comments