@@ -1242,4 +1242,80 @@ mod tests {
12421242
12431243 Ok ( ( ) )
12441244 }
1245+
1246+ #[ tokio:: test]
1247+ async fn query_storage_with_composite_key_works ( ) -> Result < ( ) > {
1248+ // Spawn a test node and prepare chain configuration via the command flow
1249+ let node = TestNode :: spawn ( ) . await ?;
1250+ let node_url = node. ws_url ( ) ;
1251+
1252+ // Provide composite key parts separately to ensure the command converts them into a tuple
1253+ let mut call_config = CallChainCommand {
1254+ pallet : Some ( "Assets" . to_string ( ) ) ,
1255+ function : Some ( "Account" . to_string ( ) ) ,
1256+ args : vec ! [
1257+ "10000" . to_string( ) , // AssetId
1258+ // Alice AccountId32 (hex) in dev networks
1259+ "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d" . to_string( ) ,
1260+ ] ,
1261+ ..Default :: default ( )
1262+ } ;
1263+
1264+ let mut cli = MockCli :: new ( )
1265+ . expect_select (
1266+ "Select a chain (type to filter):" . to_string ( ) ,
1267+ Some ( true ) ,
1268+ true ,
1269+ Some ( vec ! [ ( "Custom" . to_string( ) , "Type the chain URL manually" . to_string( ) ) ] ) ,
1270+ 0 ,
1271+ None ,
1272+ )
1273+ . expect_input ( "Which chain would you like to interact with?" , node_url. into ( ) ) ;
1274+
1275+ let chain = chain:: configure (
1276+ "Which chain would you like to interact with?" ,
1277+ node_url,
1278+ & None ,
1279+ |_| true ,
1280+ & mut cli,
1281+ )
1282+ . await ?;
1283+
1284+ // Configure the call; since pallet and storage name are provided and args present,
1285+ // this should not prompt further.
1286+ // For composite keys the command should convert the
1287+ // two args into a single tuple string argument.
1288+ let call = call_config. configure_call ( & chain, & mut cli) ?;
1289+ assert_eq ! ( call. function. pallet( ) , "Assets" ) ;
1290+ assert_eq ! ( call. function. name( ) , "Account" ) ;
1291+ assert_eq ! ( call. args. len( ) , 1 , "Composite key should be represented as a single tuple arg" ) ;
1292+
1293+ // Perform the query similar to the execute() path
1294+ if let CallItem :: Storage ( storage) = & call. function {
1295+ let keys = if let Some ( key_ty) = storage. key_id {
1296+ let metadata = chain. client . metadata ( ) ;
1297+ let registry = metadata. types ( ) ;
1298+ let type_info = registry
1299+ . resolve ( key_ty)
1300+ . ok_or ( anyhow:: anyhow!( "Failed to resolve storage key type: {key_ty}" ) ) ?;
1301+ let name = type_info. path . segments . last ( ) . unwrap_or ( & "" . to_string ( ) ) . to_string ( ) ;
1302+ let key_param = type_to_param ( & name, registry, key_ty)
1303+ . map_err ( |e| anyhow ! ( "Failed to parse storage key type: {e}" ) ) ?;
1304+
1305+ pop_chains:: parse_dispatchable_arguments ( & [ key_param] , call. args . clone ( ) )
1306+ . map_err ( |e| anyhow ! ( "Failed to parse storage arguments: {e}" ) ) ?
1307+ } else {
1308+ vec ! [ ]
1309+ } ;
1310+
1311+ // Execute the storage query; result may be None if the (AssetId, AccountId)
1312+ // combination does not exist on the fresh test chain, but the query should succeed
1313+ // without errors.
1314+ let _maybe_value = storage. query ( & chain. client , keys) . await ?;
1315+ } else {
1316+ panic ! ( "Expected a storage query" ) ;
1317+ }
1318+
1319+ cli. verify ( )
1320+ }
12451321}
0 commit comments