Skip to content

Commit 1ff1d69

Browse files
authored
Merge pull request #2202 from onflow/cf/name-flag
Add name flag for aliasing
2 parents 535cefc + b898bc1 commit 1ff1d69

3 files changed

Lines changed: 149 additions & 6 deletions

File tree

internal/dependencymanager/dependencyinstaller.go

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

108109
func (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

335358
func (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))
@@ -783,12 +811,13 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork
783811
}
784812

785813
func (di *DependencyInstaller) updateDependencyState(originalDependency config.Dependency, contractHash string) error {
786-
// Create the dependency to save, preserving aliases from the original
814+
// Create the dependency to save, preserving aliases and canonical from the original
787815
dep := config.Dependency{
788-
Name: originalDependency.Name,
789-
Source: originalDependency.Source,
790-
Hash: contractHash,
791-
Aliases: originalDependency.Aliases, // Preserve aliases from the original dependency
816+
Name: originalDependency.Name,
817+
Source: originalDependency.Source,
818+
Hash: contractHash,
819+
Aliases: originalDependency.Aliases,
820+
Canonical: originalDependency.Canonical,
792821
}
793822

794823
isNewDep := di.State.Dependencies().ByName(dep.Name) == nil

internal/dependencymanager/dependencyinstaller_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,3 +743,110 @@ func TestAliasedImportHandling(t *testing.T) {
743743
assert.NotNil(t, fileContent)
744744
})
745745
}
746+
747+
func TestDependencyInstallerWithAlias(t *testing.T) {
748+
logger := output.NewStdoutLogger(output.NoneLog)
749+
_, state, _ := util.TestMocks(t)
750+
751+
serviceAcc, _ := state.EmulatorServiceAccount()
752+
serviceAddress := serviceAcc.Address
753+
754+
t.Run("AddBySourceStringWithName", func(t *testing.T) {
755+
gw := mocks.DefaultMockGateway()
756+
757+
gw.GetAccount.Run(func(args mock.Arguments) {
758+
addr := args.Get(1).(flow.Address)
759+
assert.Equal(t, addr.String(), serviceAddress.String())
760+
acc := tests.NewAccountWithAddress(addr.String())
761+
acc.Contracts = map[string][]byte{
762+
"NumberFormatter": []byte("access(all) contract NumberFormatter {}"),
763+
}
764+
gw.GetAccount.Return(acc, nil)
765+
})
766+
767+
di := &DependencyInstaller{
768+
Gateways: map[string]gateway.Gateway{
769+
config.EmulatorNetwork.Name: gw.Mock,
770+
},
771+
Logger: logger,
772+
State: state,
773+
SaveState: true,
774+
TargetDir: "",
775+
SkipDeployments: true,
776+
SkipAlias: true,
777+
Name: "NumberFormatterCustom",
778+
dependencies: make(map[string]config.Dependency),
779+
}
780+
781+
err := di.AddBySourceString(fmt.Sprintf("%s://%s.%s", config.EmulatorNetwork.Name, serviceAddress.String(), "NumberFormatter"))
782+
assert.NoError(t, err, "Failed to add dependency with import alias")
783+
784+
// Check that the dependency was added with the import alias name
785+
dep := state.Dependencies().ByName("NumberFormatterCustom")
786+
assert.NotNil(t, dep, "Dependency should exist with import alias name")
787+
assert.Equal(t, "NumberFormatter", dep.Source.ContractName, "Source ContractName should be the actual contract name")
788+
assert.Equal(t, "NumberFormatter", dep.Canonical, "Canonical should be set to the actual contract name for import aliasing")
789+
790+
// Check that the contract was added with canonical field for Cadence import aliasing
791+
contract, err := state.Contracts().ByName("NumberFormatterCustom")
792+
assert.NoError(t, err, "Contract should exist")
793+
assert.Equal(t, "NumberFormatter", contract.Canonical, "Contract Canonical should be set for import aliasing")
794+
795+
// Check that the file was created with the actual contract name
796+
filePath := fmt.Sprintf("imports/%s/NumberFormatter.cdc", serviceAddress.String())
797+
fileContent, err := state.ReaderWriter().ReadFile(filePath)
798+
assert.NoError(t, err, "Contract file should exist at imports/address/NumberFormatter.cdc")
799+
assert.NotNil(t, fileContent)
800+
})
801+
802+
t.Run("AddByCoreContractNameWithName", func(t *testing.T) {
803+
// Mock the gateway to return FlowToken contract
804+
gw := mocks.DefaultMockGateway()
805+
gw.GetAccount.Run(func(args mock.Arguments) {
806+
addr := args.Get(1).(flow.Address)
807+
acc := tests.NewAccountWithAddress(addr.String())
808+
acc.Contracts = map[string][]byte{
809+
"FlowToken": []byte("access(all) contract FlowToken {}"),
810+
}
811+
gw.GetAccount.Return(acc, nil)
812+
})
813+
814+
di := &DependencyInstaller{
815+
Gateways: map[string]gateway.Gateway{
816+
config.MainnetNetwork.Name: gw.Mock,
817+
},
818+
Logger: logger,
819+
State: state,
820+
SaveState: true,
821+
TargetDir: "",
822+
SkipDeployments: true,
823+
SkipAlias: true,
824+
Name: "FlowTokenCustom",
825+
dependencies: make(map[string]config.Dependency),
826+
}
827+
828+
err := di.AddByCoreContractName("FlowToken")
829+
assert.NoError(t, err, "Failed to add core contract with import alias")
830+
831+
// Check that the dependency was added with the import alias name
832+
dep := state.Dependencies().ByName("FlowTokenCustom")
833+
assert.NotNil(t, dep, "Dependency should exist with import alias name")
834+
assert.Equal(t, "FlowToken", dep.Source.ContractName, "Source ContractName should be FlowToken")
835+
assert.Equal(t, "FlowToken", dep.Canonical, "Canonical should be set to FlowToken for import aliasing")
836+
})
837+
838+
t.Run("AddAllByNetworkAddressWithNameError", func(t *testing.T) {
839+
// This test doesn't need gateways since it returns an error before making any gateway calls
840+
di := &DependencyInstaller{
841+
Logger: logger,
842+
State: state,
843+
SaveState: true,
844+
TargetDir: "",
845+
Name: "SomeName",
846+
}
847+
848+
err := di.AddAllByNetworkAddress(fmt.Sprintf("%s://%s", config.EmulatorNetwork.Name, serviceAddress.String()))
849+
assert.Error(t, err, "Should error when using --name with network://address format")
850+
assert.Contains(t, err.Error(), "--name flag is not supported when installing all contracts", "Error message should mention name flag limitation")
851+
})
852+
}

internal/dependencymanager/install.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,16 @@ Examples:
7474
flow dependencies install --deployment-account my-account FlowToken
7575
flow dependencies install -d my-account FlowToken
7676
77+
8. Install a dependency with an import alias (for Cadence import aliasing):
78+
flow dependencies install --name USDF testnet://0x1234abcd.FiatToken
79+
flow dependencies install --name MyToken mainnet://0xabcd1234.TokenContract
80+
This creates an import alias that enables "import FiatToken as USDF from 0x1234abcd" syntax in Cadence.
81+
7782
Flags:
7883
• --deployment-account, -d: Specify the account name to use for deployments (skips deployment account prompt)
7984
• --skip-deployments: Skip adding the dependency to deployments
8085
• --skip-alias: Skip prompting for an alias
86+
• --name: Import alias name for the dependency (sets canonical field for Cadence import aliasing, e.g., --name USDF)
8187
8288
Note:
8389
• Using 'network://address' will attempt to install all contracts deployed at that address.
@@ -94,7 +100,8 @@ flow dependencies install FlowToken
94100
flow dependencies install DeFiActions
95101
flow dependencies install FlowToken NonFungibleToken DeFiActions
96102
flow dependencies install --deployment-account my-account FlowToken
97-
flow dependencies install -d my-account FlowToken`,
103+
flow dependencies install -d my-account FlowToken
104+
flow dependencies install --name USDF testnet://0x1234abcd.FiatToken`,
98105
Args: cobra.ArbitraryArgs,
99106
},
100107
Flags: &installFlags,

0 commit comments

Comments
 (0)