@@ -103,6 +103,7 @@ type DependencyFlags struct {
103103 skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"`
104104 skipUpdatePrompts bool `default:"false" flag:"skip-update-prompts" info:"Skip prompting to update existing dependencies"`
105105 deploymentAccount string `default:"" flag:"deployment-account,d" info:"Account name to use for deployments (skips deployment account prompt)"`
106+ name string `default:"" flag:"name" info:"Import alias name for the dependency (sets canonical field for Cadence import aliasing)"`
106107}
107108
108109func (f * DependencyFlags ) AddToCommand (cmd * cobra.Command ) {
@@ -125,6 +126,7 @@ type DependencyInstaller struct {
125126 SkipDeployments bool
126127 SkipAlias bool
127128 DeploymentAccount string
129+ Name string
128130 logs categorizedLogs
129131 dependencies map [string ]config.Dependency
130132 accountAliases map [string ]map [string ]flowsdk.Address // network -> account -> alias
@@ -164,6 +166,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat
164166 SkipDeployments : flags .skipDeployments ,
165167 SkipAlias : flags .skipAlias ,
166168 DeploymentAccount : flags .deploymentAccount ,
169+ Name : flags .name ,
167170 dependencies : make (map [string ]config.Dependency ),
168171 logs : categorizedLogs {},
169172 accountAliases : make (map [string ]map [string ]flowsdk.Address ),
@@ -222,6 +225,13 @@ func (di *DependencyInstaller) AddBySourceString(depSource string) error {
222225 },
223226 }
224227
228+ // If a name is provided, use it as the import alias and set canonical for Cadence import aliasing
229+ // This enables "import OriginalContract as AliasName from address" syntax
230+ if di .Name != "" {
231+ dep .Name = di .Name
232+ dep .Canonical = depContractName
233+ }
234+
225235 return di .Add (dep )
226236}
227237
@@ -257,6 +267,13 @@ func (di *DependencyInstaller) AddByCoreContractName(coreContractName string) er
257267 },
258268 }
259269
270+ // If a name is provided, use it as the import alias and set canonical for Cadence import aliasing
271+ // This enables "import OriginalContract as AliasName from address" syntax
272+ if di .Name != "" {
273+ dep .Name = di .Name
274+ dep .Canonical = depContractName
275+ }
276+
260277 return di .Add (dep )
261278}
262279
@@ -275,6 +292,12 @@ func (di *DependencyInstaller) AddByDefiContractName(defiContractName string) er
275292 return fmt .Errorf ("contract %s not found in DeFi actions contracts" , defiContractName )
276293 }
277294
295+ // If a custom name is provided, use it as the dependency name and set canonical
296+ if di .Name != "" {
297+ targetDep .Name = di .Name
298+ targetDep .Canonical = defiContractName
299+ }
300+
278301 return di .Add (* targetDep )
279302}
280303
@@ -333,6 +356,11 @@ func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error {
333356}
334357
335358func (di * DependencyInstaller ) AddAllByNetworkAddress (sourceStr string ) error {
359+ // Check if name flag is set - not supported when installing all contracts at an address
360+ if di .Name != "" {
361+ return fmt .Errorf ("--name flag is not supported when installing all contracts at an address (network://address). Please specify a specific contract using network://address.ContractName format" )
362+ }
363+
336364 network , address := ParseNetworkAddressString (sourceStr )
337365
338366 accountContracts , err := di .getContracts (network , flowsdk .HexToAddress (address ))
@@ -495,16 +523,26 @@ func (di *DependencyInstaller) fetchDependenciesWithDepth(dependency config.Depe
495523 if program .HasAddressImports () {
496524 imports := program .AddressImportDeclarations ()
497525 for _ , imp := range imports {
498- importContractName := imp .Imports [0 ].Identifier .Identifier
526+
527+ actualContractName := imp .Imports [0 ].Identifier .Identifier
499528 importAddress := flowsdk .HexToAddress (imp .Location .String ())
500529
530+ // Check if this import has an alias (e.g., "import FUSD as FUSD1 from 0xaddress")
531+ // If aliased, use the alias as the dependency name so "import FUSD1" resolves correctly
532+ dependencyName := actualContractName
533+ if imp .Imports [0 ].Alias .Identifier != "" {
534+ dependencyName = imp .Imports [0 ].Alias .Identifier
535+ }
536+
501537 // Create a dependency for the import
538+ // Name is the alias (or actual name if not aliased) - this is what gets resolved in imports
539+ // ContractName is the actual contract name on chain - this is what gets fetched
502540 importDependency := config.Dependency {
503- Name : importContractName ,
541+ Name : dependencyName ,
504542 Source : config.Source {
505543 NetworkName : networkName ,
506544 Address : importAddress ,
507- ContractName : importContractName ,
545+ ContractName : actualContractName ,
508546 },
509547 }
510548
@@ -567,13 +605,13 @@ func (di *DependencyInstaller) handleFoundContract(dependency config.Dependency,
567605 program .ConvertAddressImports ()
568606 contractData := string (program .CodeWithUnprocessedImports ())
569607
570- existingDependency := di .State .Dependencies ().ByName (contractName )
608+ existingDependency := di .State .Dependencies ().ByName (dependency . Name )
571609
572610 // If a dependency by this name already exists and its remote source network or address does not match,
573611 // allow it only if an existing alias matches the incoming network+address; otherwise terminate.
574612 if existingDependency != nil && (existingDependency .Source .NetworkName != networkName || existingDependency .Source .Address .String () != contractAddr ) {
575- if ! di .existingAliasMatches (contractName , networkName , contractAddr ) {
576- di .Logger .Info (fmt .Sprintf ("%s A dependency named %s already exists with a different remote source. Please fix the conflict and retry." , util .PrintEmoji ("🚫" ), contractName ))
613+ if ! di .existingAliasMatches (dependency . Name , networkName , contractAddr ) {
614+ di .Logger .Info (fmt .Sprintf ("%s A dependency named %s already exists with a different remote source. Please fix the conflict and retry." , util .PrintEmoji ("🚫" ), dependency . Name ))
577615 os .Exit (0 )
578616 return nil
579617 }
@@ -588,7 +626,7 @@ func (di *DependencyInstaller) handleFoundContract(dependency config.Dependency,
588626 // Find existing pending prompt for this contract or create new one
589627 found := false
590628 for i := range di .pendingPrompts {
591- if di .pendingPrompts [i ].contractName == contractName {
629+ if di .pendingPrompts [i ].contractName == dependency . Name {
592630 di .pendingPrompts [i ].needsUpdate = true
593631 di .pendingPrompts [i ].updateHash = originalContractDataHash
594632 found = true
@@ -597,7 +635,7 @@ func (di *DependencyInstaller) handleFoundContract(dependency config.Dependency,
597635 }
598636 if ! found {
599637 di .pendingPrompts = append (di .pendingPrompts , pendingPrompt {
600- contractName : contractName ,
638+ contractName : dependency . Name ,
601639 networkName : networkName ,
602640 needsUpdate : true ,
603641 updateHash : originalContractDataHash ,
@@ -607,7 +645,7 @@ func (di *DependencyInstaller) handleFoundContract(dependency config.Dependency,
607645 }
608646
609647 // Check if this is a new dependency before updating state
610- isNewDep := di .State .Dependencies ().ByName (contractName ) == nil
648+ isNewDep := di .State .Dependencies ().ByName (dependency . Name ) == nil
611649
612650 err := di .updateDependencyState (dependency , originalContractDataHash )
613651 if err != nil {
@@ -618,7 +656,7 @@ func (di *DependencyInstaller) handleFoundContract(dependency config.Dependency,
618656 // Handle additional tasks for new dependencies or when contract file doesn't exist
619657 // This makes sure prompts are collected for new dependencies regardless of whether contract file exists
620658 if isNewDep || ! di .contractFileExists (contractAddr , contractName ) {
621- err := di .handleAdditionalDependencyTasks (networkName , contractName )
659+ err := di .handleAdditionalDependencyTasks (networkName , dependency . Name )
622660 if err != nil {
623661 di .Logger .Error (fmt .Sprintf ("Error handling additional dependency tasks: %v" , err ))
624662 return err
@@ -775,19 +813,29 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork
775813}
776814
777815func (di * DependencyInstaller ) updateDependencyState (originalDependency config.Dependency , contractHash string ) error {
778- // Create the dependency to save, preserving aliases from the original
816+ // Create the dependency to save, preserving aliases and canonical from the original
779817 dep := config.Dependency {
780- Name : originalDependency .Name ,
781- Source : originalDependency .Source ,
782- Hash : contractHash ,
783- Aliases : originalDependency .Aliases , // Preserve aliases from the original dependency
818+ Name : originalDependency .Name ,
819+ Source : originalDependency .Source ,
820+ Hash : contractHash ,
821+ Aliases : originalDependency .Aliases ,
822+ Canonical : originalDependency .Canonical ,
784823 }
785824
786825 isNewDep := di .State .Dependencies ().ByName (dep .Name ) == nil
787826
788827 di .State .Dependencies ().AddOrUpdate (dep )
789828 di .State .Contracts ().AddDependencyAsContract (dep , originalDependency .Source .NetworkName )
790829
830+ // If this is an aliased import (Name differs from ContractName), set the Canonical field on the contract
831+ // This enables flowkit to generate the correct "import X as Y from address" syntax
832+ if dep .Name != dep .Source .ContractName {
833+ contract , err := di .State .Contracts ().ByName (dep .Name )
834+ if err == nil && contract != nil {
835+ contract .Canonical = dep .Source .ContractName
836+ }
837+ }
838+
791839 if isNewDep {
792840 msg := util .MessageWithEmojiPrefix ("✅" , fmt .Sprintf ("%s added to flow.json" , dep .Name ))
793841 di .logs .stateUpdates = append (di .logs .stateUpdates , msg )
0 commit comments