@@ -994,3 +994,210 @@ fn contract_alias_add_rejects_path_traversal() {
994994 . stderr ( predicate:: str:: contains ( "Invalid name" ) ) ;
995995 } ) ;
996996}
997+
998+ #[ test]
999+ fn native_alias_resolves_to_native_asset_contract ( ) {
1000+ TestEnv :: with_default ( |sandbox| {
1001+ let native_sac = sandbox
1002+ . new_assert_cmd ( "contract" )
1003+ . args ( [ "id" , "asset" , "--asset" , "native" ] )
1004+ . assert ( )
1005+ . success ( )
1006+ . stdout_as_str ( ) ;
1007+
1008+ let resolved = sandbox
1009+ . new_assert_cmd ( "contract" )
1010+ . args ( [ "alias" , "show" , "native" ] )
1011+ . assert ( )
1012+ . success ( )
1013+ . stdout_as_str ( ) ;
1014+
1015+ assert_eq ! ( native_sac, resolved) ;
1016+ } ) ;
1017+ }
1018+
1019+ #[ test]
1020+ fn cannot_add_reserved_native_alias ( ) {
1021+ TestEnv :: with_default ( |sandbox| {
1022+ sandbox
1023+ . new_assert_cmd ( "contract" )
1024+ . arg ( "alias" )
1025+ . arg ( "add" )
1026+ . arg ( "native" )
1027+ . arg ( "--id=CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE" )
1028+ . assert ( )
1029+ . failure ( )
1030+ . stderr ( predicate:: str:: contains ( "reserved" ) ) ;
1031+ } ) ;
1032+ }
1033+
1034+ #[ test]
1035+ fn can_remove_shadowed_native_alias ( ) {
1036+ TestEnv :: with_default ( |sandbox| {
1037+ // A `native` alias created before it became reserved can still be
1038+ // removed to clean up the shadowed file.
1039+ let contract_ids = sandbox. config_dir ( ) . join ( "contract-ids" ) ;
1040+ fs:: create_dir_all ( & contract_ids) . unwrap ( ) ;
1041+ fs:: write (
1042+ contract_ids. join ( "native.json" ) ,
1043+ r#"{"ids":{"Standalone Network ; February 2017":"CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"}}"# ,
1044+ )
1045+ . unwrap ( ) ;
1046+
1047+ sandbox
1048+ . new_assert_cmd ( "contract" )
1049+ . args ( [ "alias" , "remove" , "native" ] )
1050+ . assert ( )
1051+ . success ( ) ;
1052+
1053+ // The shadowed entry is gone; only the built-in remains.
1054+ sandbox
1055+ . new_assert_cmd ( "contract" )
1056+ . args ( [ "alias" , "ls" ] )
1057+ . assert ( )
1058+ . success ( )
1059+ . stdout (
1060+ predicate:: str:: contains ( "(built-in)" )
1061+ . and ( predicate:: str:: contains ( "(disabled)" ) . not ( ) ) ,
1062+ ) ;
1063+ } ) ;
1064+ }
1065+
1066+ #[ test]
1067+ fn alias_ls_always_shows_builtin_native ( ) {
1068+ TestEnv :: with_default ( |sandbox| {
1069+ // A user alias makes a network group appear in the listing.
1070+ sandbox
1071+ . new_assert_cmd ( "contract" )
1072+ . args ( [
1073+ "alias" ,
1074+ "add" ,
1075+ "my-token" ,
1076+ "--id=CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE" ,
1077+ ] )
1078+ . assert ( )
1079+ . success ( ) ;
1080+
1081+ sandbox
1082+ . new_assert_cmd ( "contract" )
1083+ . args ( [ "alias" , "ls" ] )
1084+ . assert ( )
1085+ . success ( )
1086+ . stdout (
1087+ predicate:: str:: contains ( "native:" ) . and ( predicate:: str:: contains ( "(built-in)" ) ) ,
1088+ ) ;
1089+ } ) ;
1090+ }
1091+
1092+ #[ test]
1093+ fn alias_ls_marks_preexisting_native_alias_disabled ( ) {
1094+ TestEnv :: with_default ( |sandbox| {
1095+ // Simulate a `native` alias created before it became a reserved
1096+ // built-in. It is now shadowed and should be listed as disabled.
1097+ let contract_ids = sandbox. config_dir ( ) . join ( "contract-ids" ) ;
1098+ fs:: create_dir_all ( & contract_ids) . unwrap ( ) ;
1099+ fs:: write (
1100+ contract_ids. join ( "native.json" ) ,
1101+ r#"{"ids":{"Standalone Network ; February 2017":"CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"}}"# ,
1102+ )
1103+ . unwrap ( ) ;
1104+
1105+ sandbox
1106+ . new_assert_cmd ( "contract" )
1107+ . args ( [ "alias" , "ls" ] )
1108+ . assert ( )
1109+ . success ( )
1110+ . stdout (
1111+ predicate:: str:: contains ( "(disabled)" ) . and ( predicate:: str:: contains ( "(built-in)" ) ) ,
1112+ ) ;
1113+ } ) ;
1114+ }
1115+
1116+ #[ test]
1117+ fn remove_native_without_stored_file_reports_reserved ( ) {
1118+ TestEnv :: with_default ( |sandbox| {
1119+ // No stored `native.json` exists (the normal case, since `alias add
1120+ // native` is blocked). Removal must say the alias is reserved, matching
1121+ // what `ls` and `show` report, not "no contract found".
1122+ sandbox
1123+ . new_assert_cmd ( "contract" )
1124+ . args ( [ "alias" , "remove" , "native" ] )
1125+ . assert ( )
1126+ . failure ( )
1127+ . stderr (
1128+ predicate:: str:: contains ( "reserved" )
1129+ . and ( predicate:: str:: contains ( "no contract found" ) . not ( ) ) ,
1130+ ) ;
1131+ } ) ;
1132+ }
1133+
1134+ #[ test]
1135+ fn cannot_generate_reserved_native_key ( ) {
1136+ TestEnv :: with_default ( |sandbox| {
1137+ sandbox
1138+ . new_assert_cmd ( "keys" )
1139+ . arg ( "generate" )
1140+ . arg ( "--seed" )
1141+ . arg ( "0000000000000000" )
1142+ . arg ( "native" )
1143+ . assert ( )
1144+ . failure ( )
1145+ . stderr ( predicate:: str:: contains ( "reserved" ) ) ;
1146+ } ) ;
1147+ }
1148+
1149+ #[ test]
1150+ fn cannot_add_reserved_native_key ( ) {
1151+ TestEnv :: with_default ( |sandbox| {
1152+ sandbox
1153+ . new_assert_cmd ( "keys" )
1154+ . arg ( "add" )
1155+ . arg ( "native" )
1156+ . env (
1157+ "STELLAR_SECRET_KEY" ,
1158+ "SBEQMTXGCLDFQG3OXMRSMGLKJCPROAHB5GZCCGVZERDI645LCCCRLFGY" ,
1159+ )
1160+ . assert ( )
1161+ . failure ( )
1162+ . stderr ( predicate:: str:: contains ( "reserved" ) ) ;
1163+ } ) ;
1164+ }
1165+
1166+ #[ test]
1167+ fn shadowed_native_alias_errors_on_show ( ) {
1168+ TestEnv :: with_default ( |sandbox| {
1169+ // A `native` alias stored before the name became reserved points at a
1170+ // different contract; resolving it must error rather than silently
1171+ // returning the native asset contract.
1172+ let contract_ids = sandbox. config_dir ( ) . join ( "contract-ids" ) ;
1173+ fs:: create_dir_all ( & contract_ids) . unwrap ( ) ;
1174+ fs:: write (
1175+ contract_ids. join ( "native.json" ) ,
1176+ r#"{"ids":{"Standalone Network ; February 2017":"CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE"}}"# ,
1177+ )
1178+ . unwrap ( ) ;
1179+
1180+ sandbox
1181+ . new_assert_cmd ( "contract" )
1182+ . args ( [ "alias" , "show" , "native" ] )
1183+ . assert ( )
1184+ . failure ( )
1185+ . stderr ( predicate:: str:: contains ( "reserved" ) ) ;
1186+ } ) ;
1187+ }
1188+
1189+ #[ test]
1190+ fn cannot_deploy_with_reserved_native_alias ( ) {
1191+ // The reserved alias must be rejected before building, simulating, or
1192+ // deploying, so this fails fast without needing a network.
1193+ TestEnv :: with_default ( |sandbox| {
1194+ sandbox
1195+ . new_assert_cmd ( "contract" )
1196+ . arg ( "deploy" )
1197+ . arg ( "--alias=native" )
1198+ . arg ( "--wasm=/does/not/matter.wasm" )
1199+ . assert ( )
1200+ . failure ( )
1201+ . stderr ( predicate:: str:: contains ( "reserved" ) ) ;
1202+ } ) ;
1203+ }
0 commit comments