From 2b40ec714445f36a843e6672b20765ade0cb766e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:09:40 -0800 Subject: [PATCH 01/95] Setup contract install command --- cmd/flow/main.go | 7 +++++++ internal/contracts/contracts.go | 16 ++++++++++++++++ internal/contracts/install.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 internal/contracts/contracts.go create mode 100644 internal/contracts/install.go diff --git a/cmd/flow/main.go b/cmd/flow/main.go index 1b77738b6..0ba65c605 100644 --- a/cmd/flow/main.go +++ b/cmd/flow/main.go @@ -22,6 +22,8 @@ package main import ( "os" + "github.com/onflow/flow-cli/internal/contracts" + "github.com/spf13/cobra" "github.com/onflow/flow-cli/internal/accounts" @@ -87,8 +89,13 @@ func main() { cmd.AddCommand(snapshot.Cmd) cmd.AddCommand(super.FlixCmd) cmd.AddCommand(super.GenerateCommand) + cmd.AddCommand(contracts.Cmd) command.InitFlags(cmd) + cmd.AddGroup(&cobra.Group{ + ID: "manager", + Title: "🔗 Contract Manager", + }) cmd.AddGroup(&cobra.Group{ ID: "super", Title: "🔥 Super Commands", diff --git a/internal/contracts/contracts.go b/internal/contracts/contracts.go new file mode 100644 index 000000000..6fe3d36bb --- /dev/null +++ b/internal/contracts/contracts.go @@ -0,0 +1,16 @@ +package contracts + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "contracts", + Short: "Manage contracts and dependencies", + TraverseChildren: true, + GroupID: "manager", +} + +func init() { + installCommand.AddToParent(Cmd) +} diff --git a/internal/contracts/install.go b/internal/contracts/install.go new file mode 100644 index 000000000..adeeb304f --- /dev/null +++ b/internal/contracts/install.go @@ -0,0 +1,32 @@ +package contracts + +import ( + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/internal/command" + "github.com/spf13/cobra" +) + +type flagsCollection struct{} + +var installFlags = flagsCollection{} + +var installCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "install", + Short: "Install contract and dependencies.", + }, + Flags: &installFlags, + RunS: install, +} + +func install( + _ []string, + _ command.GlobalFlags, + logger output.Logger, + _ flowkit.Services, + _ *flowkit.State, +) (result command.Result, err error) { + logger.Info("Fetching contract and dependencies...") + return nil, err +} From 857ebb69d397f6dce34058abb40ac631df3a3327 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:04:56 -0800 Subject: [PATCH 02/95] Get contracts from account --- internal/contracts/install.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index adeeb304f..c31d261a5 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -1,9 +1,13 @@ package contracts import ( + "context" + "fmt" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" + flowsdk "github.com/onflow/flow-go-sdk" "github.com/spf13/cobra" ) @@ -21,12 +25,29 @@ var installCommand = &command.Command{ } func install( - _ []string, + args []string, _ command.GlobalFlags, logger output.Logger, - _ flowkit.Services, + flow flowkit.Services, _ *flowkit.State, ) (result command.Result, err error) { - logger.Info("Fetching contract and dependencies...") + if len(args) < 1 { + return nil, fmt.Errorf("please specify a contract address") + } + + address := flowsdk.HexToAddress(args[0]) + logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", address)) + account, err := flow.GetAccount(context.Background(), address) + if err != nil { + return nil, err + } + + fmt.Println("account: ", len(account.Contracts)) + + for name, code := range account.Contracts { + fmt.Println("name: ", name) + fmt.Println("code: ", string(code)) + } + return nil, err } From 97203cdf62bd39997ac0a35903369ce9f2a21194 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:48:31 -0800 Subject: [PATCH 03/95] Transform dependencies to config --- flowkit/config/config.go | 11 +++-- flowkit/config/dependency.go | 25 ++++++++++ flowkit/config/json/dependencies.go | 58 ++++++++++++++++++++++++ flowkit/config/json/dependencies_test.go | 33 ++++++++++++++ flowkit/state.go | 4 ++ 5 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 flowkit/config/dependency.go create mode 100644 flowkit/config/json/dependencies.go create mode 100644 flowkit/config/json/dependencies_test.go diff --git a/flowkit/config/config.go b/flowkit/config/config.go index fb75c7bdf..3781ba32b 100644 --- a/flowkit/config/config.go +++ b/flowkit/config/config.go @@ -33,11 +33,12 @@ import ( // Accounts defines Flow accounts and their addresses, private key and more properties // Deployments describes which contracts should be deployed to which accounts type Config struct { - Emulators Emulators - Contracts Contracts - Networks Networks - Accounts Accounts - Deployments Deployments + Emulators Emulators + Contracts Contracts + Dependencies Dependencies + Networks Networks + Accounts Accounts + Deployments Deployments } type KeyType string diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go new file mode 100644 index 000000000..7fce7215d --- /dev/null +++ b/flowkit/config/dependency.go @@ -0,0 +1,25 @@ +package config + +type RemoteSource struct { + NetworkName string + Address string + ContractName string +} + +type Dependency struct { + Name string + RemoteSource RemoteSource + Aliases Aliases +} + +type Dependencies []Dependency + +func (d *Dependencies) ByName(name string) *Dependency { + for i, dep := range *d { + if dep.Name == name { + return &(*d)[i] + } + } + + return nil +} diff --git a/flowkit/config/json/dependencies.go b/flowkit/config/json/dependencies.go new file mode 100644 index 000000000..293f1229a --- /dev/null +++ b/flowkit/config/json/dependencies.go @@ -0,0 +1,58 @@ +package json + +import ( + "fmt" + "strings" + + "github.com/onflow/flow-cli/flowkit/config" +) + +type dependency struct { + RemoteSource string `json:"remoteSource"` + Aliases map[string]string `json:"aliases"` +} + +type jsonDependencies map[string]dependency + +func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { + deps := make(config.Dependencies, 0) + + for dependencyName, dependencies := range j { + depNetwork, depAddress, depContractName, err := parseRemoteSourceString(dependencies.RemoteSource) + if err != nil { + return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) + } + + dep := config.Dependency{ + Name: dependencyName, + RemoteSource: config.RemoteSource{ + NetworkName: depNetwork, + Address: depAddress, + ContractName: depContractName, + }, + } + + deps = append(deps, dep) + } + + return deps, nil +} + +func parseRemoteSourceString(s string) (network, address, contractName string, err error) { + fmt.Printf("Parsing: %s\n", s) + + parts := strings.Split(s, "/") + if len(parts) != 2 { + return "", "", "", fmt.Errorf("invalid format") + } + network = parts[0] + + subParts := strings.Split(parts[1], ".") + if len(subParts) != 2 { + return "", "", "", fmt.Errorf("invalid format") + } + address = subParts[0] + contractName = subParts[1] + + return network, address, contractName, nil +} diff --git a/flowkit/config/json/dependencies_test.go b/flowkit/config/json/dependencies_test.go new file mode 100644 index 000000000..8f0c94b1d --- /dev/null +++ b/flowkit/config/json/dependencies_test.go @@ -0,0 +1,33 @@ +package json + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_ConfigDependencies(t *testing.T) { + b := []byte(`{ + "HelloWorld": { + "remoteSource": "testnet/0x0123123123.HelloWorld", + "aliases": { + "testnet": "0x0123123123", + "mainnet": "0x0123123124" + } + } + }`) + + var jsonDependencies jsonDependencies + err := json.Unmarshal(b, &jsonDependencies) + assert.NoError(t, err) + + dependencies, err := jsonDependencies.transformToConfig() + assert.NoError(t, err) + + assert.Len(t, dependencies, 1) + + dependencyOne := dependencies.ByName("HelloWorld") + + assert.NotNil(t, dependencyOne) +} diff --git a/flowkit/state.go b/flowkit/state.go index 4832ab87f..1b5038bdf 100644 --- a/flowkit/state.go +++ b/flowkit/state.go @@ -109,6 +109,10 @@ func (p *State) Contracts() *config.Contracts { return &p.conf.Contracts } +func (p *State) Dependencies() *config.Dependencies { + return &p.conf.Dependencies +} + // Accounts get accounts. func (p *State) Accounts() *accounts.Accounts { return p.accounts From 693e482a2d6457bec7990c50396afa00e277eb17 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:58:25 -0800 Subject: [PATCH 04/95] Add transform to json --- flowkit/config/json/dependencies.go | 42 ++++++++++++++++++++++++ flowkit/config/json/dependencies_test.go | 31 +++++++++++++++-- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/flowkit/config/json/dependencies.go b/flowkit/config/json/dependencies.go index 293f1229a..46bdb0b9f 100644 --- a/flowkit/config/json/dependencies.go +++ b/flowkit/config/json/dependencies.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-cli/flowkit/config" ) @@ -23,6 +25,14 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) } + aliases := make(config.Aliases, 0) + for network, address := range dependencies.Aliases { + aliases = append(aliases, config.Alias{ + Network: network, + Address: flow.HexToAddress(address), + }) + } + dep := config.Dependency{ Name: dependencyName, RemoteSource: config.RemoteSource{ @@ -30,6 +40,7 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { Address: depAddress, ContractName: depContractName, }, + Aliases: aliases, } deps = append(deps, dep) @@ -38,6 +49,25 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { return deps, nil } +func (j jsonDependencies) transformDependenciesToJSON(configDependencies config.Dependencies) jsonDependencies { + jsonDeps := jsonDependencies{} + + for _, dep := range configDependencies { + + aliases := make(map[string]string) + for _, alias := range dep.Aliases { + aliases[alias.Network] = alias.Address.String() + } + + jsonDeps[dep.Name] = dependency{ + RemoteSource: buildRemoteSourceString(dep.RemoteSource), + Aliases: aliases, + } + } + + return jsonDeps +} + func parseRemoteSourceString(s string) (network, address, contractName string, err error) { fmt.Printf("Parsing: %s\n", s) @@ -56,3 +86,15 @@ func parseRemoteSourceString(s string) (network, address, contractName string, e return network, address, contractName, nil } + +func buildRemoteSourceString(remoteSource config.RemoteSource) string { + var builder strings.Builder + + builder.WriteString(remoteSource.NetworkName) + builder.WriteString("/") + builder.WriteString(remoteSource.Address) + builder.WriteString(".") + builder.WriteString(remoteSource.ContractName) + + return builder.String() +} diff --git a/flowkit/config/json/dependencies_test.go b/flowkit/config/json/dependencies_test.go index 8f0c94b1d..22ec0499e 100644 --- a/flowkit/config/json/dependencies_test.go +++ b/flowkit/config/json/dependencies_test.go @@ -10,10 +10,10 @@ import ( func Test_ConfigDependencies(t *testing.T) { b := []byte(`{ "HelloWorld": { - "remoteSource": "testnet/0x0123123123.HelloWorld", + "remoteSource": "testnet/0x877931736ee77cff.HelloWorld", "aliases": { - "testnet": "0x0123123123", - "mainnet": "0x0123123124" + "testnet": "877931736ee77cff", + "mainnet": "0b2a3299cc857e29" } } }`) @@ -30,4 +30,29 @@ func Test_ConfigDependencies(t *testing.T) { dependencyOne := dependencies.ByName("HelloWorld") assert.NotNil(t, dependencyOne) + assert.Len(t, dependencyOne.Aliases, 2) +} + +func Test_TransformDependenciesToJSON(t *testing.T) { + b := []byte(`{ + "HelloWorld": { + "remoteSource": "testnet/0x877931736ee77cff.HelloWorld", + "aliases": { + "mainnet": "0b2a3299cc857e29", + "testnet": "877931736ee77cff" + } + } + }`) + + var jsonDependencies jsonDependencies + err := json.Unmarshal(b, &jsonDependencies) + assert.NoError(t, err) + + dependencies, err := jsonDependencies.transformToConfig() + assert.NoError(t, err) + + j := jsonDependencies.transformDependenciesToJSON(dependencies) + x, _ := json.Marshal(j) + + assert.Equal(t, cleanSpecialChars(b), cleanSpecialChars(x)) } From 44b760c154c4babbe1044ff0cc454b7efa8f3c47 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:00:21 -0800 Subject: [PATCH 05/95] Change to Address type --- flowkit/config/dependency.go | 4 +++- flowkit/config/json/dependencies.go | 4 ++-- flowkit/config/json/dependencies_test.go | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 7fce7215d..c01dbc74d 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -1,8 +1,10 @@ package config +import "github.com/onflow/flow-go-sdk" + type RemoteSource struct { NetworkName string - Address string + Address flow.Address ContractName string } diff --git a/flowkit/config/json/dependencies.go b/flowkit/config/json/dependencies.go index 46bdb0b9f..419b202f8 100644 --- a/flowkit/config/json/dependencies.go +++ b/flowkit/config/json/dependencies.go @@ -37,7 +37,7 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { Name: dependencyName, RemoteSource: config.RemoteSource{ NetworkName: depNetwork, - Address: depAddress, + Address: flow.HexToAddress(depAddress), ContractName: depContractName, }, Aliases: aliases, @@ -92,7 +92,7 @@ func buildRemoteSourceString(remoteSource config.RemoteSource) string { builder.WriteString(remoteSource.NetworkName) builder.WriteString("/") - builder.WriteString(remoteSource.Address) + builder.WriteString(remoteSource.Address.String()) builder.WriteString(".") builder.WriteString(remoteSource.ContractName) diff --git a/flowkit/config/json/dependencies_test.go b/flowkit/config/json/dependencies_test.go index 22ec0499e..a6d28e6e1 100644 --- a/flowkit/config/json/dependencies_test.go +++ b/flowkit/config/json/dependencies_test.go @@ -10,7 +10,7 @@ import ( func Test_ConfigDependencies(t *testing.T) { b := []byte(`{ "HelloWorld": { - "remoteSource": "testnet/0x877931736ee77cff.HelloWorld", + "remoteSource": "testnet/877931736ee77cff.HelloWorld", "aliases": { "testnet": "877931736ee77cff", "mainnet": "0b2a3299cc857e29" @@ -36,7 +36,7 @@ func Test_ConfigDependencies(t *testing.T) { func Test_TransformDependenciesToJSON(t *testing.T) { b := []byte(`{ "HelloWorld": { - "remoteSource": "testnet/0x877931736ee77cff.HelloWorld", + "remoteSource": "testnet/877931736ee77cff.HelloWorld", "aliases": { "mainnet": "0b2a3299cc857e29", "testnet": "877931736ee77cff" From 3f60a29806b2bcee28892493b0d4a34e19ca7809 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:11:29 -0800 Subject: [PATCH 06/95] Change file name --- flowkit/config/json/{dependencies.go => dependency.go} | 0 flowkit/config/json/{dependencies_test.go => dependency_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename flowkit/config/json/{dependencies.go => dependency.go} (100%) rename flowkit/config/json/{dependencies_test.go => dependency_test.go} (100%) diff --git a/flowkit/config/json/dependencies.go b/flowkit/config/json/dependency.go similarity index 100% rename from flowkit/config/json/dependencies.go rename to flowkit/config/json/dependency.go diff --git a/flowkit/config/json/dependencies_test.go b/flowkit/config/json/dependency_test.go similarity index 100% rename from flowkit/config/json/dependencies_test.go rename to flowkit/config/json/dependency_test.go From 087ffebbb45362339110a7af3c75b85aa29e51df Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:30:29 -0800 Subject: [PATCH 07/95] Change function --- flowkit/config/json/dependency.go | 2 +- flowkit/config/json/dependency_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 419b202f8..10f890ecd 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -49,7 +49,7 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { return deps, nil } -func (j jsonDependencies) transformDependenciesToJSON(configDependencies config.Dependencies) jsonDependencies { +func transformDependenciesToJSON(configDependencies config.Dependencies) jsonDependencies { jsonDeps := jsonDependencies{} for _, dep := range configDependencies { diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index a6d28e6e1..b2e9fda18 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -51,7 +51,7 @@ func Test_TransformDependenciesToJSON(t *testing.T) { dependencies, err := jsonDependencies.transformToConfig() assert.NoError(t, err) - j := jsonDependencies.transformDependenciesToJSON(dependencies) + j := transformDependenciesToJSON(dependencies) x, _ := json.Marshal(j) assert.Equal(t, cleanSpecialChars(b), cleanSpecialChars(x)) From cf58b644de81d367836e20fc96821404fa8b4f98 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:38:10 -0800 Subject: [PATCH 08/95] Get dependencies on install --- flowkit/config/dependency.go | 11 +++++++++ flowkit/config/dependency_test.go | 26 +++++++++++++++++++++ flowkit/config/json/config.go | 38 +++++++++++++++++++------------ flowkit/config/loader.go | 4 ++++ flowkit/config/processor.go | 11 +++++---- flowkit/schema.json | 11 +++++++++ internal/contracts/install.go | 33 +++++++++++---------------- 7 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 flowkit/config/dependency_test.go diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index c01dbc74d..10ef8d3a8 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -25,3 +25,14 @@ func (d *Dependencies) ByName(name string) *Dependency { return nil } + +func (d *Dependencies) AddOrUpdate(dep Dependency) { + for i, dependency := range *d { + if dependency.Name == dep.Name { + (*d)[i] = dep + return + } + } + + *d = append(*d, dep) +} diff --git a/flowkit/config/dependency_test.go b/flowkit/config/dependency_test.go new file mode 100644 index 000000000..33482d449 --- /dev/null +++ b/flowkit/config/dependency_test.go @@ -0,0 +1,26 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDependencies_ByName(t *testing.T) { + dependencies := Dependencies{ + Dependency{Name: "mydep"}, + } + + dep := dependencies.ByName("mydep") + assert.NotNil(t, dep) +} + +func TestDependencies_AddOrUpdate(t *testing.T) { + dependencies := Dependencies{} + dependencies.AddOrUpdate(Dependency{Name: "mydep"}) + + assert.Len(t, dependencies, 1) + + dep := dependencies.ByName("mydep") + assert.NotNil(t, dep) +} diff --git a/flowkit/config/json/config.go b/flowkit/config/json/config.go index 0611b622f..2ad3b83bb 100644 --- a/flowkit/config/json/config.go +++ b/flowkit/config/json/config.go @@ -27,11 +27,12 @@ import ( // jsonConfig implements JSON format for persisting and parsing configuration. type jsonConfig struct { - Emulators jsonEmulators `json:"emulators,omitempty"` - Contracts jsonContracts `json:"contracts,omitempty"` - Networks jsonNetworks `json:"networks,omitempty"` - Accounts jsonAccounts `json:"accounts,omitempty"` - Deployments jsonDeployments `json:"deployments,omitempty"` + Emulators jsonEmulators `json:"emulators,omitempty"` + Contracts jsonContracts `json:"contracts,omitempty"` + Dependencies jsonDependencies `json:"dependencies,omitempty"` + Networks jsonNetworks `json:"networks,omitempty"` + Accounts jsonAccounts `json:"accounts,omitempty"` + Deployments jsonDeployments `json:"deployments,omitempty"` } func (j *jsonConfig) transformToConfig() (*config.Config, error) { @@ -45,6 +46,11 @@ func (j *jsonConfig) transformToConfig() (*config.Config, error) { return nil, err } + dependencies, err := j.Dependencies.transformToConfig() + if err != nil { + return nil, err + } + networks, err := j.Networks.transformToConfig() if err != nil { return nil, err @@ -61,11 +67,12 @@ func (j *jsonConfig) transformToConfig() (*config.Config, error) { } conf := &config.Config{ - Emulators: emulators, - Contracts: contracts, - Networks: networks, - Accounts: accounts, - Deployments: deployments, + Emulators: emulators, + Contracts: contracts, + Dependencies: dependencies, + Networks: networks, + Accounts: accounts, + Deployments: deployments, } return conf, nil @@ -73,11 +80,12 @@ func (j *jsonConfig) transformToConfig() (*config.Config, error) { func transformConfigToJSON(config *config.Config) jsonConfig { return jsonConfig{ - Emulators: transformEmulatorsToJSON(config.Emulators), - Contracts: transformContractsToJSON(config.Contracts), - Networks: transformNetworksToJSON(config.Networks), - Accounts: transformAccountsToJSON(config.Accounts), - Deployments: transformDeploymentsToJSON(config.Deployments), + Emulators: transformEmulatorsToJSON(config.Emulators), + Contracts: transformContractsToJSON(config.Contracts), + Dependencies: transformDependenciesToJSON(config.Dependencies), + Networks: transformNetworksToJSON(config.Networks), + Accounts: transformAccountsToJSON(config.Accounts), + Deployments: transformDeploymentsToJSON(config.Deployments), } } diff --git a/flowkit/config/loader.go b/flowkit/config/loader.go index d46f7b1e7..d012c2f23 100644 --- a/flowkit/config/loader.go +++ b/flowkit/config/loader.go @@ -201,6 +201,10 @@ func (l *Loader) composeConfig(baseConf *Config, conf *Config) { for _, contract := range conf.Contracts { baseConf.Contracts.AddOrUpdate(contract) } + for _, dependency := range conf.Dependencies { + fmt.Println("dependency in LOADER: ", dependency.Name) + baseConf.Dependencies.AddOrUpdate(dependency) + } for _, deployment := range conf.Deployments { baseConf.Deployments.AddOrUpdate(deployment) } diff --git a/flowkit/config/processor.go b/flowkit/config/processor.go index cdcc6924a..883bafade 100644 --- a/flowkit/config/processor.go +++ b/flowkit/config/processor.go @@ -26,11 +26,12 @@ import ( // processorRun all pre-processors. func processorRun(raw []byte) ([]byte, error) { type config struct { - Accounts map[string]map[string]any `json:"accounts,omitempty"` - Contracts any `json:"contracts,omitempty"` - Networks any `json:"networks,omitempty"` - Deployments any `json:"deployments,omitempty"` - Emulators any `json:"emulators,omitempty"` + Accounts map[string]map[string]any `json:"accounts,omitempty"` + Contracts any `json:"contracts,omitempty"` + Dependencies any `json:"dependencies,omitempty"` + Networks any `json:"networks,omitempty"` + Deployments any `json:"deployments,omitempty"` + Emulators any `json:"emulators,omitempty"` } var conf config diff --git a/flowkit/schema.json b/flowkit/schema.json index 082b31434..2c4634b03 100644 --- a/flowkit/schema.json +++ b/flowkit/schema.json @@ -159,6 +159,9 @@ "contracts": { "$ref": "#/$defs/jsonContracts" }, + "dependencies": { + "$ref": "#/$defs/jsonDependencies" + }, "networks": { "$ref": "#/$defs/jsonNetworks" }, @@ -211,6 +214,14 @@ }, "type": "object" }, + "jsonDependencies": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/jsonDependencies" + } + }, + "type": "object" + }, "jsonDeployment": { "patternProperties": { ".*": { diff --git a/internal/contracts/install.go b/internal/contracts/install.go index c31d261a5..d9843d238 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -1,13 +1,11 @@ package contracts import ( - "context" "fmt" "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" - flowsdk "github.com/onflow/flow-go-sdk" "github.com/spf13/cobra" ) @@ -25,28 +23,23 @@ var installCommand = &command.Command{ } func install( - args []string, + _ []string, _ command.GlobalFlags, logger output.Logger, flow flowkit.Services, - _ *flowkit.State, + state *flowkit.State, ) (result command.Result, err error) { - if len(args) < 1 { - return nil, fmt.Errorf("please specify a contract address") - } - - address := flowsdk.HexToAddress(args[0]) - logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", address)) - account, err := flow.GetAccount(context.Background(), address) - if err != nil { - return nil, err - } - - fmt.Println("account: ", len(account.Contracts)) - - for name, code := range account.Contracts { - fmt.Println("name: ", name) - fmt.Println("code: ", string(code)) + //address := flowsdk.HexToAddress(args[0]) + //logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", address)) + //account, err := flow.GetAccount(context.Background(), address) + //if err != nil { + // return nil, err + //} + // + //fmt.Println("account: ", len(account.Contracts)) + + for _, dependency := range *state.Dependencies() { + fmt.Println("dependency: ", dependency.Name) } return nil, err From 8712171afbd61e07a92b1ce8c695d50d362e583a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:51:14 -0800 Subject: [PATCH 09/95] Get contracts by account --- internal/contracts/install.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index d9843d238..d42700683 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -1,8 +1,11 @@ package contracts import ( + "context" "fmt" + flowsdk "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" @@ -29,17 +32,22 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - //address := flowsdk.HexToAddress(args[0]) - //logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", address)) - //account, err := flow.GetAccount(context.Background(), address) - //if err != nil { - // return nil, err - //} - // - //fmt.Println("account: ", len(account.Contracts)) for _, dependency := range *state.Dependencies() { fmt.Println("dependency: ", dependency.Name) + fmt.Println("dependency remote source address: ", dependency.RemoteSource.Address.String()) + fmt.Println("dependency remote source contract name: ", dependency.RemoteSource.ContractName) + + depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) + logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", depAddress)) + account, err := flow.GetAccount(context.Background(), depAddress) + if err != nil { + return nil, err + } + + for _, contract := range account.Contracts { + fmt.Println("contract: ", string(contract)) + } } return nil, err From cd29310365c8a7594ab15abffcd5589151dc811b Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:47:37 -0800 Subject: [PATCH 10/95] Parse for identifier and imports --- internal/contracts/install.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index d42700683..0cdb2a4c9 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/onflow/cadence/runtime/parser" + flowsdk "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-cli/flowkit" @@ -46,7 +48,13 @@ func install( } for _, contract := range account.Contracts { - fmt.Println("contract: ", string(contract)) + parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) + if err != nil { + return nil, err + } + + fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) + fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) } } From 665c748409ac8a342203394270edc8231be40d14 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Dec 2023 13:30:08 -0800 Subject: [PATCH 11/95] Get import data --- internal/contracts/install.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 0cdb2a4c9..14d9b32fa 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -55,6 +55,12 @@ func install( fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) + + for _, importDeclaration := range parsedProgram.ImportDeclarations() { + fmt.Println("Import String: ", importDeclaration.String()) + fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) + fmt.Println("Import Location: ", importDeclaration.Location) + } } } From dff666f61f922c2dfa277450f68208d52548a5c6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Dec 2023 13:59:42 -0800 Subject: [PATCH 12/95] Break out to FetchDependencies func --- internal/contracts/install.go | 46 +++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 14d9b32fa..724f7b737 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -27,6 +27,31 @@ var installCommand = &command.Command{ RunS: install, } +func FetchDependencies(flow flowkit.Services, address flowsdk.Address) error { + account, err := flow.GetAccount(context.Background(), address) + if err != nil { + return err + } + + for _, contract := range account.Contracts { + parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) + if err != nil { + return err + } + + fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) + fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) + + for _, importDeclaration := range parsedProgram.ImportDeclarations() { + fmt.Println("Import String: ", importDeclaration.String()) + fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) + fmt.Println("Import Location: ", importDeclaration.Location) + } + } + + return nil +} + func install( _ []string, _ command.GlobalFlags, @@ -42,25 +67,10 @@ func install( depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", depAddress)) - account, err := flow.GetAccount(context.Background(), depAddress) - if err != nil { - return nil, err - } - - for _, contract := range account.Contracts { - parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) - if err != nil { - return nil, err - } - fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) - fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) - - for _, importDeclaration := range parsedProgram.ImportDeclarations() { - fmt.Println("Import String: ", importDeclaration.String()) - fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) - fmt.Println("Import Location: ", importDeclaration.Location) - } + err := FetchDependencies(flow, depAddress) + if err != nil { + fmt.Println("Error:", err) } } From 0532cf6f73273eac0671f63c3a5f4810ca323c26 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:25:02 -0800 Subject: [PATCH 13/95] Check if created and create if not --- internal/contracts/install.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 724f7b737..59e4c5f28 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -3,6 +3,8 @@ package contracts import ( "context" "fmt" + "os" + "path/filepath" "github.com/onflow/cadence/runtime/parser" @@ -27,6 +29,23 @@ var installCommand = &command.Command{ RunS: install, } +func ContractExists(address, contractName string) bool { + path := filepath.Join("imports", address, contractName) + _, err := os.Stat(path) + return !os.IsNotExist(err) +} + +func CreateContractFile(address, contractName, data string) error { + path := filepath.Join("imports", address, contractName) + + dir := filepath.Dir(path) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + + return os.WriteFile(path, []byte(data), 0644) +} + func FetchDependencies(flow flowkit.Services, address flowsdk.Address) error { account, err := flow.GetAccount(context.Background(), address) if err != nil { @@ -42,6 +61,19 @@ func FetchDependencies(flow flowkit.Services, address flowsdk.Address) error { fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) + contractName := parsedProgram.SoleContractDeclaration().Identifier + + fileExists := ContractExists(address.String(), contractName.String()) + if !fileExists { + fmt.Println("Create file!") + err := CreateContractFile(address.String(), contractName.String(), string(contract)) + if err == nil { + fmt.Println("File created!") + } + } else { + fmt.Println("File already exists!") + } + for _, importDeclaration := range parsedProgram.ImportDeclarations() { fmt.Println("Import String: ", importDeclaration.String()) fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) From 348395742b0ef9f480ed39dbc702d3408e1ada98 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:06:38 -0800 Subject: [PATCH 14/95] Only do file creation/checking for requested dependency --- internal/contracts/install.go | 37 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 59e4c5f28..d0e91948e 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -46,12 +46,13 @@ func CreateContractFile(address, contractName, data string) error { return os.WriteFile(path, []byte(data), 0644) } -func FetchDependencies(flow flowkit.Services, address flowsdk.Address) error { +func FetchDependencies(flow flowkit.Services, address flowsdk.Address, contractName string) error { account, err := flow.GetAccount(context.Background(), address) if err != nil { return err } + // TODO: Should only get the contract you need for _, contract := range account.Contracts { parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) if err != nil { @@ -61,23 +62,25 @@ func FetchDependencies(flow flowkit.Services, address flowsdk.Address) error { fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) - contractName := parsedProgram.SoleContractDeclaration().Identifier - - fileExists := ContractExists(address.String(), contractName.String()) - if !fileExists { - fmt.Println("Create file!") - err := CreateContractFile(address.String(), contractName.String(), string(contract)) - if err == nil { - fmt.Println("File created!") + parsedContractName := parsedProgram.SoleContractDeclaration().Identifier + + if parsedContractName.String() == contractName { + fileExists := ContractExists(address.String(), parsedContractName.String()) + if !fileExists { + fmt.Println("Create file!") + err := CreateContractFile(address.String(), parsedContractName.String(), string(contract)) + if err == nil { + fmt.Println("File created!") + } + } else { + fmt.Println("File already exists!") } - } else { - fmt.Println("File already exists!") - } - for _, importDeclaration := range parsedProgram.ImportDeclarations() { - fmt.Println("Import String: ", importDeclaration.String()) - fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) - fmt.Println("Import Location: ", importDeclaration.Location) + for _, importDeclaration := range parsedProgram.ImportDeclarations() { + fmt.Println("Import String: ", importDeclaration.String()) + fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) + fmt.Println("Import Location: ", importDeclaration.Location) + } } } @@ -100,7 +103,7 @@ func install( depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", depAddress)) - err := FetchDependencies(flow, depAddress) + err := FetchDependencies(flow, depAddress, dependency.RemoteSource.ContractName) if err != nil { fmt.Println("Error:", err) } From 1a2fc225e8e660f5799199963135e05940edf394 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:07:54 -0800 Subject: [PATCH 15/95] Remove comment --- internal/contracts/install.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index d0e91948e..48c344d4d 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -52,7 +52,6 @@ func FetchDependencies(flow flowkit.Services, address flowsdk.Address, contractN return err } - // TODO: Should only get the contract you need for _, contract := range account.Contracts { parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) if err != nil { From 68980999c0c38062be42fb85627ece6be7363acd Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:54:57 -0800 Subject: [PATCH 16/95] Add imports to gitgnore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2a9200fa7..9c941fa56 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ git # Ignore built CLI main *.pkey + +# Local developement file generation +imports \ No newline at end of file From e42d9ea76639454d6be511c2105eb66251b3549a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:08:36 -0800 Subject: [PATCH 17/95] Handle contract vs contract interfaces --- internal/contracts/install.go | 73 ++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 48c344d4d..57df09073 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -29,13 +29,13 @@ var installCommand = &command.Command{ RunS: install, } -func ContractExists(address, contractName string) bool { +func contractFileExists(address, contractName string) bool { path := filepath.Join("imports", address, contractName) _, err := os.Stat(path) return !os.IsNotExist(err) } -func CreateContractFile(address, contractName, data string) error { +func createContractFile(address, contractName, data string) error { path := filepath.Join("imports", address, contractName) dir := filepath.Dir(path) @@ -46,39 +46,67 @@ func CreateContractFile(address, contractName, data string) error { return os.WriteFile(path, []byte(data), 0644) } -func FetchDependencies(flow flowkit.Services, address flowsdk.Address, contractName string) error { +func handleFoundContract(contractAddr, contractName, contractData string) error { + if !contractFileExists(contractAddr, contractName) { + fmt.Println("Create file!") + if err := createContractFile(contractAddr, contractName, contractData); err != nil { + return fmt.Errorf("failed to create contract file: %v", err) + } + fmt.Println("File created!") + } + + return nil +} + +func fetchDependencies(flow flowkit.Services, address flowsdk.Address, contractName string) error { account, err := flow.GetAccount(context.Background(), address) if err != nil { - return err + return fmt.Errorf("failed to get account: %v", err) + } + if account == nil { + return fmt.Errorf("account is nil for address: %s", address) + } + + if account.Contracts == nil { + return fmt.Errorf("contracts are nil for account: %s", address) } for _, contract := range account.Contracts { parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) if err != nil { - return err + return fmt.Errorf("failed to parse program: %v", err) } - fmt.Println("Contract Name: ", parsedProgram.SoleContractDeclaration().Identifier) - fmt.Println("Imports: ", parsedProgram.ImportDeclarations()) + if parsedProgram == nil { + return fmt.Errorf("parsed program is nil") + } - parsedContractName := parsedProgram.SoleContractDeclaration().Identifier + var parsedContractName string - if parsedContractName.String() == contractName { - fileExists := ContractExists(address.String(), parsedContractName.String()) - if !fileExists { - fmt.Println("Create file!") - err := CreateContractFile(address.String(), parsedContractName.String(), string(contract)) - if err == nil { - fmt.Println("File created!") - } - } else { - fmt.Println("File already exists!") + if contractDeclaration := parsedProgram.SoleContractDeclaration(); contractDeclaration != nil { + parsedContractName = contractDeclaration.Identifier.String() + } else if contractInterfaceDeclaration := parsedProgram.SoleContractInterfaceDeclaration(); contractInterfaceDeclaration != nil { + parsedContractName = contractInterfaceDeclaration.Identifier.String() + } else { + continue + } + + fmt.Println("Parsed Contract Name: ", parsedContractName) + + if parsedContractName == contractName { + fmt.Println("Contract found!") + if err := handleFoundContract(address.String(), parsedContractName, string(contract)); err != nil { + return fmt.Errorf("failed to handle found contract: %v", err) } for _, importDeclaration := range parsedProgram.ImportDeclarations() { - fmt.Println("Import String: ", importDeclaration.String()) - fmt.Println("Import Identifiers: ", importDeclaration.Identifiers) - fmt.Println("Import Location: ", importDeclaration.Location) + importName := importDeclaration.Identifiers[0].String() + importAddress := flowsdk.HexToAddress(importDeclaration.Location.String()) + + err := fetchDependencies(flow, importAddress, importName) + if err != nil { + return err + } } } } @@ -102,9 +130,10 @@ func install( depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", depAddress)) - err := FetchDependencies(flow, depAddress, dependency.RemoteSource.ContractName) + err := fetchDependencies(flow, depAddress, dependency.RemoteSource.ContractName) if err != nil { fmt.Println("Error:", err) + return nil, err } } From 4bcfcf18f2cae40cb07e685142a59cde6c1b7d7a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:18:34 -0800 Subject: [PATCH 18/95] Organize code for clarity --- internal/contracts/fileutils.go | 23 +++++++++++ internal/contracts/install.go | 70 +++++++++++---------------------- 2 files changed, 45 insertions(+), 48 deletions(-) create mode 100644 internal/contracts/fileutils.go diff --git a/internal/contracts/fileutils.go b/internal/contracts/fileutils.go new file mode 100644 index 000000000..3649f1ee4 --- /dev/null +++ b/internal/contracts/fileutils.go @@ -0,0 +1,23 @@ +package contracts + +import ( + "os" + "path/filepath" +) + +func contractFileExists(address, contractName string) bool { + path := filepath.Join("imports", address, contractName) + _, err := os.Stat(path) + return !os.IsNotExist(err) +} + +func createContractFile(address, contractName, data string) error { + path := filepath.Join("imports", address, contractName) + + dir := filepath.Dir(path) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + + return os.WriteFile(path, []byte(data), 0644) +} diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 57df09073..6a9b30fbf 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -3,8 +3,8 @@ package contracts import ( "context" "fmt" - "os" - "path/filepath" + + "github.com/onflow/flow-cli/flowkit/config" "github.com/onflow/cadence/runtime/parser" @@ -29,36 +29,39 @@ var installCommand = &command.Command{ RunS: install, } -func contractFileExists(address, contractName string) bool { - path := filepath.Join("imports", address, contractName) - _, err := os.Stat(path) - return !os.IsNotExist(err) -} - -func createContractFile(address, contractName, data string) error { - path := filepath.Join("imports", address, contractName) - - dir := filepath.Dir(path) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return err +func install( + _ []string, + _ command.GlobalFlags, + logger output.Logger, + flow flowkit.Services, + state *flowkit.State, +) (result command.Result, err error) { + for _, dependency := range *state.Dependencies() { + if err := processDependency(flow, logger, dependency); err != nil { + fmt.Println("Error:", err) + return nil, err + } } + return nil, nil +} - return os.WriteFile(path, []byte(data), 0644) +func processDependency(flow flowkit.Services, logger output.Logger, dependency config.Dependency) error { + depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) + return fetchDependencies(flow, logger, depAddress, dependency.RemoteSource.ContractName) } func handleFoundContract(contractAddr, contractName, contractData string) error { if !contractFileExists(contractAddr, contractName) { - fmt.Println("Create file!") if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) } - fmt.Println("File created!") } return nil } -func fetchDependencies(flow flowkit.Services, address flowsdk.Address, contractName string) error { +func fetchDependencies(flow flowkit.Services, logger output.Logger, address flowsdk.Address, contractName string) error { + logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) account, err := flow.GetAccount(context.Background(), address) if err != nil { return fmt.Errorf("failed to get account: %v", err) @@ -91,10 +94,7 @@ func fetchDependencies(flow flowkit.Services, address flowsdk.Address, contractN continue } - fmt.Println("Parsed Contract Name: ", parsedContractName) - if parsedContractName == contractName { - fmt.Println("Contract found!") if err := handleFoundContract(address.String(), parsedContractName, string(contract)); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } @@ -103,7 +103,7 @@ func fetchDependencies(flow flowkit.Services, address flowsdk.Address, contractN importName := importDeclaration.Identifiers[0].String() importAddress := flowsdk.HexToAddress(importDeclaration.Location.String()) - err := fetchDependencies(flow, importAddress, importName) + err := fetchDependencies(flow, logger, importAddress, importName) if err != nil { return err } @@ -113,29 +113,3 @@ func fetchDependencies(flow flowkit.Services, address flowsdk.Address, contractN return nil } - -func install( - _ []string, - _ command.GlobalFlags, - logger output.Logger, - flow flowkit.Services, - state *flowkit.State, -) (result command.Result, err error) { - - for _, dependency := range *state.Dependencies() { - fmt.Println("dependency: ", dependency.Name) - fmt.Println("dependency remote source address: ", dependency.RemoteSource.Address.String()) - fmt.Println("dependency remote source contract name: ", dependency.RemoteSource.ContractName) - - depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - logger.Info(fmt.Sprintf("Fetching contract and dependencies for %s", depAddress)) - - err := fetchDependencies(flow, depAddress, dependency.RemoteSource.ContractName) - if err != nil { - fmt.Println("Error:", err) - return nil, err - } - } - - return nil, err -} From 1a014bbc4970ea05513adde3abf7a783a4045178 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:09:38 -0800 Subject: [PATCH 19/95] Switch to contract installer pattern --- internal/contracts/contract-installer.go | 107 +++++++++++++++++++++++ internal/contracts/install.go | 85 +----------------- 2 files changed, 111 insertions(+), 81 deletions(-) create mode 100644 internal/contracts/contract-installer.go diff --git a/internal/contracts/contract-installer.go b/internal/contracts/contract-installer.go new file mode 100644 index 000000000..45581675a --- /dev/null +++ b/internal/contracts/contract-installer.go @@ -0,0 +1,107 @@ +package contracts + +import ( + "context" + "fmt" + + "github.com/onflow/cadence/runtime/parser" + + "github.com/onflow/flow-cli/flowkit/config" + flowsdk "github.com/onflow/flow-go-sdk" + + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" +) + +type ContractInstaller struct { + FlowService flowkit.Services + Logger output.Logger + State *flowkit.State +} + +func NewContractInstaller(flow flowkit.Services, logger output.Logger, state *flowkit.State) *ContractInstaller { + return &ContractInstaller{ + FlowService: flow, + Logger: logger, + State: state, + } +} + +func (ci *ContractInstaller) install() error { + for _, dependency := range *ci.State.Dependencies() { + if err := ci.processDependency(dependency); err != nil { + ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) + return err + } + } + return nil +} + +func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { + depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) + return ci.fetchDependencies(depAddress, dependency.RemoteSource.ContractName) +} + +func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contractName string) error { + ci.Logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) + account, err := ci.FlowService.GetAccount(context.Background(), address) + if err != nil { + return fmt.Errorf("failed to get account: %v", err) + } + if account == nil { + return fmt.Errorf("account is nil for address: %s", address) + } + + if account.Contracts == nil { + return fmt.Errorf("contracts are nil for account: %s", address) + } + + for _, contract := range account.Contracts { + parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) + if err != nil { + return fmt.Errorf("failed to parse program: %v", err) + } + + if parsedProgram == nil { + return fmt.Errorf("parsed program is nil") + } + + var parsedContractName string + + if contractDeclaration := parsedProgram.SoleContractDeclaration(); contractDeclaration != nil { + parsedContractName = contractDeclaration.Identifier.String() + } else if contractInterfaceDeclaration := parsedProgram.SoleContractInterfaceDeclaration(); contractInterfaceDeclaration != nil { + parsedContractName = contractInterfaceDeclaration.Identifier.String() + } else { + continue + } + + if parsedContractName == contractName { + if err := ci.handleFoundContract(address.String(), parsedContractName, string(contract)); err != nil { + return fmt.Errorf("failed to handle found contract: %v", err) + } + + for _, importDeclaration := range parsedProgram.ImportDeclarations() { + importName := importDeclaration.Identifiers[0].String() + importAddress := flowsdk.HexToAddress(importDeclaration.Location.String()) + + err := ci.fetchDependencies(importAddress, importName) + if err != nil { + return err + } + } + } + } + + return nil +} + +func (ci *ContractInstaller) handleFoundContract(contractAddr, contractName, contractData string) error { + if !contractFileExists(contractAddr, contractName) { + if err := createContractFile(contractAddr, contractName, contractData); err != nil { + return fmt.Errorf("failed to create contract file: %v", err) + } + } + + return nil +} diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 6a9b30fbf..8fcd89bb7 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -1,15 +1,8 @@ package contracts import ( - "context" "fmt" - "github.com/onflow/flow-cli/flowkit/config" - - "github.com/onflow/cadence/runtime/parser" - - flowsdk "github.com/onflow/flow-go-sdk" - "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" @@ -36,80 +29,10 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - for _, dependency := range *state.Dependencies() { - if err := processDependency(flow, logger, dependency); err != nil { - fmt.Println("Error:", err) - return nil, err - } + installer := NewContractInstaller(flow, logger, state) + if err := installer.install(); err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err } return nil, nil } - -func processDependency(flow flowkit.Services, logger output.Logger, dependency config.Dependency) error { - depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return fetchDependencies(flow, logger, depAddress, dependency.RemoteSource.ContractName) -} - -func handleFoundContract(contractAddr, contractName, contractData string) error { - if !contractFileExists(contractAddr, contractName) { - if err := createContractFile(contractAddr, contractName, contractData); err != nil { - return fmt.Errorf("failed to create contract file: %v", err) - } - } - - return nil -} - -func fetchDependencies(flow flowkit.Services, logger output.Logger, address flowsdk.Address, contractName string) error { - logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) - account, err := flow.GetAccount(context.Background(), address) - if err != nil { - return fmt.Errorf("failed to get account: %v", err) - } - if account == nil { - return fmt.Errorf("account is nil for address: %s", address) - } - - if account.Contracts == nil { - return fmt.Errorf("contracts are nil for account: %s", address) - } - - for _, contract := range account.Contracts { - parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) - if err != nil { - return fmt.Errorf("failed to parse program: %v", err) - } - - if parsedProgram == nil { - return fmt.Errorf("parsed program is nil") - } - - var parsedContractName string - - if contractDeclaration := parsedProgram.SoleContractDeclaration(); contractDeclaration != nil { - parsedContractName = contractDeclaration.Identifier.String() - } else if contractInterfaceDeclaration := parsedProgram.SoleContractInterfaceDeclaration(); contractInterfaceDeclaration != nil { - parsedContractName = contractInterfaceDeclaration.Identifier.String() - } else { - continue - } - - if parsedContractName == contractName { - if err := handleFoundContract(address.String(), parsedContractName, string(contract)); err != nil { - return fmt.Errorf("failed to handle found contract: %v", err) - } - - for _, importDeclaration := range parsedProgram.ImportDeclarations() { - importName := importDeclaration.Identifiers[0].String() - importAddress := flowsdk.HexToAddress(importDeclaration.Location.String()) - - err := fetchDependencies(flow, logger, importAddress, importName) - if err != nil { - return err - } - } - } - } - - return nil -} From cd50f5604396705f5e22d2f0a48081fdb986dcba Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:22:52 -0800 Subject: [PATCH 20/95] Add updateState for dependencies --- internal/contracts/contract-installer.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/contracts/contract-installer.go b/internal/contracts/contract-installer.go index 45581675a..926b1118d 100644 --- a/internal/contracts/contract-installer.go +++ b/internal/contracts/contract-installer.go @@ -103,5 +103,29 @@ func (ci *ContractInstaller) handleFoundContract(contractAddr, contractName, con } } + err := ci.updateState(contractAddr, contractName) + if err != nil { + ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) + return err + } + + return nil +} + +func (ci *ContractInstaller) updateState(contractAddress, contractName string) error { + dep := config.Dependency{ + Name: contractName, + RemoteSource: config.RemoteSource{ + NetworkName: ci.FlowService.Network().Name, + Address: flowsdk.HexToAddress(contractAddress), + ContractName: contractName, + }, + } + ci.State.Dependencies().AddOrUpdate(dep) + err := ci.State.SaveDefault() + if err != nil { + return err + } + return nil } From 42f0ff4b0eecb5b5f4569a918412ac567a438975 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 12:36:24 -0800 Subject: [PATCH 21/95] Change file name --- .../contracts/{contract-installer.go => contractinstaller.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename internal/contracts/{contract-installer.go => contractinstaller.go} (100%) diff --git a/internal/contracts/contract-installer.go b/internal/contracts/contractinstaller.go similarity index 100% rename from internal/contracts/contract-installer.go rename to internal/contracts/contractinstaller.go From 45668f260dfe2fb924202d3c53ebaed6680d7ca7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:41:05 -0800 Subject: [PATCH 22/95] Convert program imports for development --- flowkit/project/program.go | 31 +++++++++++++++++++++++-------- flowkit/project/program_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/flowkit/project/program.go b/flowkit/project/program.go index 0b77bba69..2395037c5 100644 --- a/flowkit/project/program.go +++ b/flowkit/project/program.go @@ -29,10 +29,11 @@ import ( ) type Program struct { - code []byte - args []cadence.Value - location string - astProgram *ast.Program + code []byte + args []cadence.Value + location string + astProgram *ast.Program + developmentCode []byte } func NewProgram(code []byte, args []cadence.Value, location string) (*Program, error) { @@ -42,10 +43,11 @@ func NewProgram(code []byte, args []cadence.Value, location string) (*Program, e } return &Program{ - code: code, - args: args, - location: location, - astProgram: astProgram, + code: code, + args: args, + location: location, + astProgram: astProgram, + developmentCode: code, // has converted import syntax e.g. 'import "Foo"' }, nil } @@ -94,6 +96,10 @@ func (p *Program) Code() []byte { return p.code } +func (p *Program) DevelopmentCode() []byte { + return p.developmentCode +} + func (p *Program) Name() (string, error) { if len(p.astProgram.CompositeDeclarations()) > 1 || len(p.astProgram.InterfaceDeclarations()) > 1 || len(p.astProgram.CompositeDeclarations())+len(p.astProgram.InterfaceDeclarations()) > 1 { @@ -115,6 +121,14 @@ func (p *Program) Name() (string, error) { return "", fmt.Errorf("unable to determine contract name") } +func (p *Program) ConvertImports() { + code := string(p.code) + addressImportRegex := regexp.MustCompile(`import\s+(\w+)\s+from\s+0x[0-9a-fA-F]+`) + modifiedCode := addressImportRegex.ReplaceAllString(code, `import "$1"`) + + p.developmentCode = []byte(modifiedCode) +} + func (p *Program) reload() { astProgram, err := parser.ParseProgram(nil, p.code, parser.Config{}) if err != nil { @@ -122,4 +136,5 @@ func (p *Program) reload() { } p.astProgram = astProgram + p.ConvertImports() } diff --git a/flowkit/project/program_test.go b/flowkit/project/program_test.go index 161999114..69e1fe32f 100644 --- a/flowkit/project/program_test.go +++ b/flowkit/project/program_test.go @@ -160,4 +160,31 @@ func TestProgram(t *testing.T) { assert.Equal(t, string(replaced), string(program.Code())) }) + t.Run("Convert to Import Syntax", func(t *testing.T) { + code := []byte(` + import Foo from 0x123 + import "Bar" + import FooSpace from 0x124 + import "BarSpace" + + pub contract Foo {} + `) + + expected := []byte(` + import "Foo" + import "Bar" + import "FooSpace" + import "BarSpace" + + pub contract Foo {} + `) + + program, err := NewProgram(code, nil, "") + require.NoError(t, err) + + program.ConvertImports() + + assert.Equal(t, string(expected), string(program.DevelopmentCode())) + }) + } From 3ecee969aba99726465ff751383e89699fff94ce Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:45:13 -0800 Subject: [PATCH 23/95] Switch to using program struct --- flowkit/project/deployment.go | 2 +- flowkit/project/imports.go | 2 +- flowkit/project/program.go | 7 ++--- flowkit/project/program_test.go | 2 +- internal/contracts/contractinstaller.go | 39 +++++++++++-------------- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/flowkit/project/deployment.go b/flowkit/project/deployment.go index f8b4f1431..9f495a779 100644 --- a/flowkit/project/deployment.go +++ b/flowkit/project/deployment.go @@ -137,7 +137,7 @@ func (d *Deployment) conflictExists() bool { // buildDependencies iterates over all contracts and checks the imports which are added as its dependencies. func (d *Deployment) buildDependencies() error { for _, contract := range d.contracts { - for _, location := range contract.program.imports() { + for _, location := range contract.program.Imports() { // find contract by the path import importPath := absolutePath(contract.location, location) importContract, isPath := d.contractsByLocation[importPath] diff --git a/flowkit/project/imports.go b/flowkit/project/imports.go index 268b0e86e..48d916f6e 100644 --- a/flowkit/project/imports.go +++ b/flowkit/project/imports.go @@ -44,7 +44,7 @@ func NewImportReplacer(contracts []*Contract, aliases LocationAliases) *ImportRe } func (i *ImportReplacer) Replace(program *Program) (*Program, error) { - imports := program.imports() + imports := program.Imports() contractsLocations := i.getContractsLocations() for _, imp := range imports { diff --git a/flowkit/project/program.go b/flowkit/project/program.go index 2395037c5..afaa69dc2 100644 --- a/flowkit/project/program.go +++ b/flowkit/project/program.go @@ -51,11 +51,10 @@ func NewProgram(code []byte, args []cadence.Value, location string) (*Program, e }, nil } -// imports builds an array of all the import locations -// +// Imports builds an array of all the import locations // It currently supports getting import locations as identifiers or as strings. Strings locations // can represent a file or an account name, whereas identifiers represent contract names. -func (p *Program) imports() []string { +func (p *Program) Imports() []string { imports := make([]string, 0) for _, importDeclaration := range p.astProgram.ImportDeclarations() { @@ -70,7 +69,7 @@ func (p *Program) imports() []string { } func (p *Program) HasImports() bool { - return len(p.imports()) > 0 + return len(p.Imports()) > 0 } func (p *Program) replaceImport(from string, to string) *Program { diff --git a/flowkit/project/program_test.go b/flowkit/project/program_test.go index 69e1fe32f..8b7fbcd9f 100644 --- a/flowkit/project/program_test.go +++ b/flowkit/project/program_test.go @@ -73,7 +73,7 @@ func TestProgram(t *testing.T) { program, err := NewProgram(test.code, nil, "") require.NoError(t, err, fmt.Sprintf("import test %d failed", i)) assert.Equal(t, len(test.imports) > 0, program.HasImports(), fmt.Sprintf("import test %d failed", i)) - assert.Equal(t, test.imports, program.imports(), fmt.Sprintf("import test %d failed", i)) + assert.Equal(t, test.imports, program.Imports(), fmt.Sprintf("import test %d failed", i)) } }) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 926b1118d..525ca49ff 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/onflow/cadence/runtime/parser" + "github.com/onflow/flow-cli/flowkit/project" "github.com/onflow/flow-cli/flowkit/config" flowsdk "github.com/onflow/flow-go-sdk" @@ -57,37 +57,32 @@ func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contract } for _, contract := range account.Contracts { - parsedProgram, err := parser.ParseProgram(nil, contract, parser.Config{}) + + program, err := project.NewProgram(contract, nil, "") if err != nil { return fmt.Errorf("failed to parse program: %v", err) } - if parsedProgram == nil { - return fmt.Errorf("parsed program is nil") - } - - var parsedContractName string - - if contractDeclaration := parsedProgram.SoleContractDeclaration(); contractDeclaration != nil { - parsedContractName = contractDeclaration.Identifier.String() - } else if contractInterfaceDeclaration := parsedProgram.SoleContractInterfaceDeclaration(); contractInterfaceDeclaration != nil { - parsedContractName = contractInterfaceDeclaration.Identifier.String() - } else { - continue + parsedContractName, err := program.Name() + if err != nil { + return fmt.Errorf("failed to parse contract name: %v", err) } if parsedContractName == contractName { - if err := ci.handleFoundContract(address.String(), parsedContractName, string(contract)); err != nil { + program.ConvertImports() + + if err := ci.handleFoundContract(address.String(), parsedContractName, string(program.DevelopmentCode())); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } - for _, importDeclaration := range parsedProgram.ImportDeclarations() { - importName := importDeclaration.Identifiers[0].String() - importAddress := flowsdk.HexToAddress(importDeclaration.Location.String()) - - err := ci.fetchDependencies(importAddress, importName) - if err != nil { - return err + if program.HasImports() { + imports := program.Imports() + for _, imp := range imports { + importAddress := flowsdk.HexToAddress(imp) + err := ci.fetchDependencies(importAddress, imp) + if err != nil { + return err + } } } } From 5701765476797ee39e62f9241409d472f2434259 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 6 Dec 2023 17:24:25 -0800 Subject: [PATCH 24/95] Add address imports declarations check --- flowkit/flowkit.go | 7 +++--- flowkit/project/deployment.go | 2 +- flowkit/project/imports.go | 2 +- flowkit/project/program.go | 22 +++++++++++++++--- flowkit/project/program_test.go | 30 +++++++++++++++++++++++-- internal/contracts/contractinstaller.go | 8 +++---- 6 files changed, 56 insertions(+), 15 deletions(-) diff --git a/flowkit/flowkit.go b/flowkit/flowkit.go index 6004e2acf..8741fe1bf 100644 --- a/flowkit/flowkit.go +++ b/flowkit/flowkit.go @@ -275,7 +275,7 @@ func (f *Flowkit) AddContract( return flow.EmptyID, false, err } - if program.HasImports() { + if program.HasPathImports() { contracts, err := state.DeploymentContractsByNetwork(f.network) if err != nil { return flow.EmptyID, false, err @@ -811,7 +811,7 @@ func (f *Flowkit) ExecuteScript(_ context.Context, script Script, query ScriptQu return nil, err } - if program.HasImports() { + if program.HasPathImports() { contracts, err := state.DeploymentContractsByNetwork(f.network) if err != nil { return nil, err @@ -921,7 +921,7 @@ func (f *Flowkit) BuildTransaction( return nil, err } - if program.HasImports() { + if program.HasPathImports() { if f.network == config.EmptyNetwork { return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") } @@ -1051,7 +1051,6 @@ func (f *Flowkit) SendTransaction( return sentTx, res, err } - // this is added to resolve the issue with chainhash ambiguous import, // the code is not used, but it's needed to force go.mod specify and retain chainhash version // workaround for issue: https://github.com/golang/go/issues/27899 diff --git a/flowkit/project/deployment.go b/flowkit/project/deployment.go index 9f495a779..bd2467de4 100644 --- a/flowkit/project/deployment.go +++ b/flowkit/project/deployment.go @@ -137,7 +137,7 @@ func (d *Deployment) conflictExists() bool { // buildDependencies iterates over all contracts and checks the imports which are added as its dependencies. func (d *Deployment) buildDependencies() error { for _, contract := range d.contracts { - for _, location := range contract.program.Imports() { + for _, location := range contract.program.pathImports() { // find contract by the path import importPath := absolutePath(contract.location, location) importContract, isPath := d.contractsByLocation[importPath] diff --git a/flowkit/project/imports.go b/flowkit/project/imports.go index 48d916f6e..0257a6759 100644 --- a/flowkit/project/imports.go +++ b/flowkit/project/imports.go @@ -44,7 +44,7 @@ func NewImportReplacer(contracts []*Contract, aliases LocationAliases) *ImportRe } func (i *ImportReplacer) Replace(program *Program) (*Program, error) { - imports := program.Imports() + imports := program.pathImports() contractsLocations := i.getContractsLocations() for _, imp := range imports { diff --git a/flowkit/project/program.go b/flowkit/project/program.go index afaa69dc2..8689187d1 100644 --- a/flowkit/project/program.go +++ b/flowkit/project/program.go @@ -51,10 +51,26 @@ func NewProgram(code []byte, args []cadence.Value, location string) (*Program, e }, nil } +func (p *Program) AddressImportDeclarations() []*ast.ImportDeclaration { + addressImports := make([]*ast.ImportDeclaration, 0) + + for _, importDeclaration := range p.astProgram.ImportDeclarations() { + if len(importDeclaration.Identifiers) > 0 && len(importDeclaration.Location.String()) > 0 { + addressImports = append(addressImports, importDeclaration) + } + } + + return addressImports +} + +func (p *Program) HasAddressImports() bool { + return len(p.AddressImportDeclarations()) > 0 +} + // Imports builds an array of all the import locations // It currently supports getting import locations as identifiers or as strings. Strings locations // can represent a file or an account name, whereas identifiers represent contract names. -func (p *Program) Imports() []string { +func (p *Program) pathImports() []string { imports := make([]string, 0) for _, importDeclaration := range p.astProgram.ImportDeclarations() { @@ -68,8 +84,8 @@ func (p *Program) Imports() []string { return imports } -func (p *Program) HasImports() bool { - return len(p.Imports()) > 0 +func (p *Program) HasPathImports() bool { + return len(p.pathImports()) > 0 } func (p *Program) replaceImport(from string, to string) *Program { diff --git a/flowkit/project/program_test.go b/flowkit/project/program_test.go index 8b7fbcd9f..24afdd0c6 100644 --- a/flowkit/project/program_test.go +++ b/flowkit/project/program_test.go @@ -28,6 +28,32 @@ import ( func TestProgram(t *testing.T) { + t.Run("AddressImports", func(t *testing.T) { + tests := []struct { + code []byte + expectedCount int + }{ + { + code: []byte(` + import Foo from 0x123 + import "Bar" + import FooSpace from 0x124 + import "BarSpace" + + pub contract Foo {} + `), + expectedCount: 2, + }, + } + + for i, test := range tests { + program, err := NewProgram(test.code, nil, "") + require.NoError(t, err, fmt.Sprintf("AddressImports test %d failed", i)) + addressImports := program.AddressImportDeclarations() + assert.Len(t, addressImports, test.expectedCount, fmt.Sprintf("AddressImports test %d failed", i)) + } + }) + t.Run("Imports", func(t *testing.T) { tests := []struct { code []byte @@ -72,8 +98,8 @@ func TestProgram(t *testing.T) { for i, test := range tests { program, err := NewProgram(test.code, nil, "") require.NoError(t, err, fmt.Sprintf("import test %d failed", i)) - assert.Equal(t, len(test.imports) > 0, program.HasImports(), fmt.Sprintf("import test %d failed", i)) - assert.Equal(t, test.imports, program.Imports(), fmt.Sprintf("import test %d failed", i)) + assert.Equal(t, len(test.imports) > 0, program.HasPathImports(), fmt.Sprintf("import test %d failed", i)) + assert.Equal(t, test.imports, program.pathImports(), fmt.Sprintf("import test %d failed", i)) } }) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 525ca49ff..6d92df535 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -75,11 +75,11 @@ func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contract return fmt.Errorf("failed to handle found contract: %v", err) } - if program.HasImports() { - imports := program.Imports() + if program.HasAddressImports() { + imports := program.AddressImportDeclarations() for _, imp := range imports { - importAddress := flowsdk.HexToAddress(imp) - err := ci.fetchDependencies(importAddress, imp) + importAddress := flowsdk.HexToAddress(imp.Location.String()) + err := ci.fetchDependencies(importAddress, imp.Identifiers[0].String()) if err != nil { return err } From ecdd328fe0546aa022ce88aa982e656b090b4bd2 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:31:14 -0800 Subject: [PATCH 25/95] Switch gateway for dependency network --- internal/contracts/contractinstaller.go | 56 +++++++++++++++++-------- internal/contracts/install.go | 2 +- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 6d92df535..811703e30 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -1,9 +1,10 @@ package contracts import ( - "context" "fmt" + "github.com/onflow/flow-cli/flowkit/gateway" + "github.com/onflow/flow-cli/flowkit/project" "github.com/onflow/flow-cli/flowkit/config" @@ -14,16 +15,37 @@ import ( ) type ContractInstaller struct { - FlowService flowkit.Services - Logger output.Logger - State *flowkit.State + Gateways map[string]gateway.Gateway + Logger output.Logger + State *flowkit.State } -func NewContractInstaller(flow flowkit.Services, logger output.Logger, state *flowkit.State) *ContractInstaller { +func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractInstaller { + emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) + } + + testnetGateway, err := gateway.NewGrpcGateway(config.TestnetNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating testnet gateway: %v", err)) + } + + mainnetGateway, err := gateway.NewGrpcGateway(config.MainnetNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating mainnet gateway: %v", err)) + } + + gateways := map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: emulatorGateway, + config.TestnetNetwork.Name: testnetGateway, + config.MainnetNetwork.Name: mainnetGateway, + } + return &ContractInstaller{ - FlowService: flow, - Logger: logger, - State: state, + Gateways: gateways, + Logger: logger, + State: state, } } @@ -39,12 +61,12 @@ func (ci *ContractInstaller) install() error { func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return ci.fetchDependencies(depAddress, dependency.RemoteSource.ContractName) + return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.RemoteSource.ContractName) } -func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contractName string) error { +func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, contractName string) error { ci.Logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) - account, err := ci.FlowService.GetAccount(context.Background(), address) + account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %v", err) } @@ -71,7 +93,7 @@ func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contract if parsedContractName == contractName { program.ConvertImports() - if err := ci.handleFoundContract(address.String(), parsedContractName, string(program.DevelopmentCode())); err != nil { + if err := ci.handleFoundContract(networkName, address.String(), parsedContractName, string(program.DevelopmentCode())); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } @@ -79,7 +101,7 @@ func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contract imports := program.AddressImportDeclarations() for _, imp := range imports { importAddress := flowsdk.HexToAddress(imp.Location.String()) - err := ci.fetchDependencies(importAddress, imp.Identifiers[0].String()) + err := ci.fetchDependencies("testnet", importAddress, imp.Identifiers[0].String()) if err != nil { return err } @@ -91,14 +113,14 @@ func (ci *ContractInstaller) fetchDependencies(address flowsdk.Address, contract return nil } -func (ci *ContractInstaller) handleFoundContract(contractAddr, contractName, contractData string) error { +func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, contractName, contractData string) error { if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) } } - err := ci.updateState(contractAddr, contractName) + err := ci.updateState(networkName, contractAddr, contractName) if err != nil { ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err @@ -107,11 +129,11 @@ func (ci *ContractInstaller) handleFoundContract(contractAddr, contractName, con return nil } -func (ci *ContractInstaller) updateState(contractAddress, contractName string) error { +func (ci *ContractInstaller) updateState(networkName, contractAddress, contractName string) error { dep := config.Dependency{ Name: contractName, RemoteSource: config.RemoteSource{ - NetworkName: ci.FlowService.Network().Name, + NetworkName: networkName, Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, }, diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 8fcd89bb7..82deaf839 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -29,7 +29,7 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - installer := NewContractInstaller(flow, logger, state) + installer := NewContractInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 224e9da6ce82ea7c00ff7e4f29371717f2b53e80 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:40:37 -0800 Subject: [PATCH 26/95] Add command for add dependency --- flowkit/config/dependency.go | 26 +++++++++++++++- flowkit/config/json/dependency.go | 21 +------------ internal/contracts/add.go | 41 +++++++++++++++++++++++++ internal/contracts/contractinstaller.go | 22 +++++++++++++ internal/contracts/contracts.go | 1 + internal/contracts/install.go | 4 +-- 6 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 internal/contracts/add.go diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 10ef8d3a8..aff146042 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -1,6 +1,30 @@ package config -import "github.com/onflow/flow-go-sdk" +import ( + "fmt" + "strings" + + "github.com/onflow/flow-go-sdk" +) + +func ParseRemoteSourceString(s string) (network, address, contractName string, err error) { + fmt.Printf("Parsing: %s\n", s) + + parts := strings.Split(s, "/") + if len(parts) != 2 { + return "", "", "", fmt.Errorf("invalid format") + } + network = parts[0] + + subParts := strings.Split(parts[1], ".") + if len(subParts) != 2 { + return "", "", "", fmt.Errorf("invalid format") + } + address = subParts[0] + contractName = subParts[1] + + return network, address, contractName, nil +} type RemoteSource struct { NetworkName string diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 10f890ecd..ba1a7e28e 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -20,7 +20,7 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { deps := make(config.Dependencies, 0) for dependencyName, dependencies := range j { - depNetwork, depAddress, depContractName, err := parseRemoteSourceString(dependencies.RemoteSource) + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependencies.RemoteSource) if err != nil { return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) } @@ -68,25 +68,6 @@ func transformDependenciesToJSON(configDependencies config.Dependencies) jsonDep return jsonDeps } -func parseRemoteSourceString(s string) (network, address, contractName string, err error) { - fmt.Printf("Parsing: %s\n", s) - - parts := strings.Split(s, "/") - if len(parts) != 2 { - return "", "", "", fmt.Errorf("invalid format") - } - network = parts[0] - - subParts := strings.Split(parts[1], ".") - if len(subParts) != 2 { - return "", "", "", fmt.Errorf("invalid format") - } - address = subParts[0] - contractName = subParts[1] - - return network, address, contractName, nil -} - func buildRemoteSourceString(remoteSource config.RemoteSource) string { var builder strings.Builder diff --git a/internal/contracts/add.go b/internal/contracts/add.go new file mode 100644 index 000000000..9babbc8f9 --- /dev/null +++ b/internal/contracts/add.go @@ -0,0 +1,41 @@ +package contracts + +import ( + "fmt" + + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/internal/command" + "github.com/spf13/cobra" +) + +type addFlagsCollection struct{} + +var addFlags = addFlagsCollection{} + +var addCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "add", + Short: "Add a single contract and its dependencies.", + Args: cobra.ExactArgs(1), + }, + Flags: &addFlags, + RunS: add, +} + +func add( + args []string, + _ command.GlobalFlags, + logger output.Logger, + flow flowkit.Services, + state *flowkit.State, +) (result command.Result, err error) { + dep := args[0] + + installer := NewContractInstaller(logger, state) + if err := installer.add(dep); err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + return nil, nil +} diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 811703e30..6d205f9f8 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -59,6 +59,28 @@ func (ci *ContractInstaller) install() error { return nil } +func (ci *ContractInstaller) add(depRemoteSource string) error { + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) + if err != nil { + return fmt.Errorf("error parsing remote source: %w", err) + } + + dep := config.Dependency{ + Name: depContractName, + RemoteSource: config.RemoteSource{ + NetworkName: depNetwork, + Address: flowsdk.HexToAddress(depAddress), + ContractName: depContractName, + }, + } + + if err := ci.processDependency(dep); err != nil { + return fmt.Errorf("error processing dependency: %w", err) + } + + return nil +} + func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.RemoteSource.ContractName) diff --git a/internal/contracts/contracts.go b/internal/contracts/contracts.go index 6fe3d36bb..01306fa37 100644 --- a/internal/contracts/contracts.go +++ b/internal/contracts/contracts.go @@ -12,5 +12,6 @@ var Cmd = &cobra.Command{ } func init() { + addCommand.AddToParent(Cmd) installCommand.AddToParent(Cmd) } diff --git a/internal/contracts/install.go b/internal/contracts/install.go index 82deaf839..a6003862e 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -9,9 +9,9 @@ import ( "github.com/spf13/cobra" ) -type flagsCollection struct{} +type installFlagsCollection struct{} -var installFlags = flagsCollection{} +var installFlags = installFlagsCollection{} var installCommand = &command.Command{ Cmd: &cobra.Command{ From 4aaad1da41b50126a755ea25b27cb43e8442caa7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:50:30 -0800 Subject: [PATCH 27/95] Allow custom name --- internal/contracts/add.go | 6 ++++-- internal/contracts/contractinstaller.go | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/internal/contracts/add.go b/internal/contracts/add.go index 9babbc8f9..1107a4589 100644 --- a/internal/contracts/add.go +++ b/internal/contracts/add.go @@ -9,7 +9,9 @@ import ( "github.com/spf13/cobra" ) -type addFlagsCollection struct{} +type addFlagsCollection struct { + name string `default:"" flag:"name" info:"Name of the dependency"` +} var addFlags = addFlagsCollection{} @@ -33,7 +35,7 @@ func add( dep := args[0] installer := NewContractInstaller(logger, state) - if err := installer.add(dep); err != nil { + if err := installer.add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 6d205f9f8..3eb14e0d2 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -59,14 +59,22 @@ func (ci *ContractInstaller) install() error { return nil } -func (ci *ContractInstaller) add(depRemoteSource string) error { +func (ci *ContractInstaller) add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) } + var name string + + if customName != "" { + name = customName + } else { + name = depContractName + } + dep := config.Dependency{ - Name: depContractName, + Name: name, RemoteSource: config.RemoteSource{ NetworkName: depNetwork, Address: flowsdk.HexToAddress(depAddress), From 9d7996081984e08e3291f15cf1284199c536caa2 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:57:05 -0800 Subject: [PATCH 28/95] Fix assigned name being set in flow.json --- internal/contracts/contractinstaller.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 3eb14e0d2..e6d355119 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -68,6 +68,7 @@ func (ci *ContractInstaller) add(depRemoteSource, customName string) error { var name string if customName != "" { + fmt.Printf("Using custom name: %s\n", customName) name = customName } else { name = depContractName @@ -91,10 +92,10 @@ func (ci *ContractInstaller) add(depRemoteSource, customName string) error { func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.RemoteSource.ContractName) + return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) } -func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, contractName string) error { +func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { ci.Logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { @@ -123,7 +124,7 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows if parsedContractName == contractName { program.ConvertImports() - if err := ci.handleFoundContract(networkName, address.String(), parsedContractName, string(program.DevelopmentCode())); err != nil { + if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, string(program.DevelopmentCode())); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } @@ -131,7 +132,8 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows imports := program.AddressImportDeclarations() for _, imp := range imports { importAddress := flowsdk.HexToAddress(imp.Location.String()) - err := ci.fetchDependencies("testnet", importAddress, imp.Identifiers[0].String()) + contractName := imp.Identifiers[0].String() + err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) if err != nil { return err } @@ -143,14 +145,14 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows return nil } -func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, contractName, contractData string) error { +func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) } } - err := ci.updateState(networkName, contractAddr, contractName) + err := ci.updateState(networkName, contractAddr, assignedName, contractName) if err != nil { ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err @@ -159,9 +161,9 @@ func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, cont return nil } -func (ci *ContractInstaller) updateState(networkName, contractAddress, contractName string) error { +func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ - Name: contractName, + Name: assignedName, RemoteSource: config.RemoteSource{ NetworkName: networkName, Address: flowsdk.HexToAddress(contractAddress), From 00042c10f6a5a8d0d4dbf986c3c40de551a45b51 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 13 Dec 2023 09:17:56 -0800 Subject: [PATCH 29/95] Fix tests --- flowkit/state_test.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/flowkit/state_test.go b/flowkit/state_test.go index af39e923b..0be2fc511 100644 --- a/flowkit/state_test.go +++ b/flowkit/state_test.go @@ -697,8 +697,9 @@ func Test_DefaultEmulatorNotPresentInConfig(t *testing.T) { Port: 3569, ServiceAccount: "emulator-account", }}, - Contracts: config.Contracts{}, - Deployments: config.Deployments{}, + Contracts: config.Contracts{}, + Dependencies: config.Dependencies{}, + Deployments: config.Deployments{}, Accounts: config.Accounts{{ Name: "emulator-account", Address: flow.ServiceAddress(flow.Emulator), @@ -805,8 +806,9 @@ func Test_DefaultEmulatorPresentInConfig(t *testing.T) { Port: 3569, ServiceAccount: "emulator-account", }}, - Contracts: config.Contracts{}, - Deployments: config.Deployments{}, + Contracts: config.Contracts{}, + Dependencies: config.Dependencies{}, + Deployments: config.Deployments{}, Accounts: config.Accounts{{ Name: "emulator-account", Address: flow.ServiceAddress(flow.Emulator), @@ -861,8 +863,9 @@ func Test_CustomEmulatorValuesInConfig(t *testing.T) { Port: 2000, ServiceAccount: "emulator-account", }}, - Contracts: config.Contracts{}, - Deployments: config.Deployments{}, + Contracts: config.Contracts{}, + Dependencies: config.Dependencies{}, + Deployments: config.Deployments{}, Accounts: config.Accounts{{ Name: "emulator-account", Address: flow.ServiceAddress(flow.Emulator), From 6baf8823161bd488c7751ad4654211bccd1e80d3 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:32:10 -0800 Subject: [PATCH 30/95] Switch format to deps to contracts --- flowkit/config/contract.go | 19 +++++++++++++ flowkit/config/contract_test.go | 18 +++++++++++++ flowkit/config/dependency.go | 1 - flowkit/config/json/dependency.go | 36 +++++++------------------ flowkit/config/json/dependency_test.go | 19 +++---------- flowkit/config/loader.go | 1 - internal/contracts/contractinstaller.go | 1 + 7 files changed, 50 insertions(+), 45 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index bdc8d41ef..a2aa19a85 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -106,3 +106,22 @@ func (c *Contracts) Remove(name string) error { return nil } + +// AddDependencyAsContract adds a dependency as a contract if it doesn't already exist. +func (c *Contracts) AddDependencyAsContract(dependency Dependency) { + fmt.Printf("Adding dependency as contract: %s\n", dependency.Name) + contract := Contract{ + Name: dependency.Name, + Location: fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName), + Aliases: Aliases{ + Alias{ + Network: dependency.RemoteSource.NetworkName, + Address: dependency.RemoteSource.Address, + }, + }, + } + + if _, err := c.ByName(contract.Name); err != nil { + c.AddOrUpdate(contract) + } +} diff --git a/flowkit/config/contract_test.go b/flowkit/config/contract_test.go index d2389f8d9..a366104ae 100644 --- a/flowkit/config/contract_test.go +++ b/flowkit/config/contract_test.go @@ -90,3 +90,21 @@ func TestContracts_Remove_NotFound(t *testing.T) { _, err = contracts.ByName("mycontract2") assert.EqualError(t, err, "contract mycontract2 does not exist") } + +func TestContracts_AddDependencyAsContract(t *testing.T) { + contracts := Contracts{} + contracts.AddDependencyAsContract(Dependency{ + Name: "testcontract", + RemoteSource: RemoteSource{ + NetworkName: "testnet", + Address: flow.HexToAddress("0x0000000000abcdef"), + ContractName: "TestContract", + }, + }) + + assert.Len(t, contracts, 1) + + contract, err := contracts.ByName("testcontract") + assert.NoError(t, err) + assert.Equal(t, "imports/0000000000abcdef/TestContract", contract.Location) +} diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index aff146042..18e8fd162 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -35,7 +35,6 @@ type RemoteSource struct { type Dependency struct { Name string RemoteSource RemoteSource - Aliases Aliases } type Dependencies []Dependency diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index ba1a7e28e..85cf1a7ca 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -9,30 +9,22 @@ import ( "github.com/onflow/flow-cli/flowkit/config" ) -type dependency struct { - RemoteSource string `json:"remoteSource"` - Aliases map[string]string `json:"aliases"` -} - -type jsonDependencies map[string]dependency +// type dependency struct { +// RemoteSource string `json:"remoteSource"` +// } +// +// type jsonDependencies map[string]dependency +type jsonDependencies map[string]string func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { deps := make(config.Dependencies, 0) - for dependencyName, dependencies := range j { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependencies.RemoteSource) + for dependencyName, dependencySource := range j { + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependencySource) if err != nil { return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) } - aliases := make(config.Aliases, 0) - for network, address := range dependencies.Aliases { - aliases = append(aliases, config.Alias{ - Network: network, - Address: flow.HexToAddress(address), - }) - } - dep := config.Dependency{ Name: dependencyName, RemoteSource: config.RemoteSource{ @@ -40,7 +32,6 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { Address: flow.HexToAddress(depAddress), ContractName: depContractName, }, - Aliases: aliases, } deps = append(deps, dep) @@ -53,16 +44,7 @@ func transformDependenciesToJSON(configDependencies config.Dependencies) jsonDep jsonDeps := jsonDependencies{} for _, dep := range configDependencies { - - aliases := make(map[string]string) - for _, alias := range dep.Aliases { - aliases[alias.Network] = alias.Address.String() - } - - jsonDeps[dep.Name] = dependency{ - RemoteSource: buildRemoteSourceString(dep.RemoteSource), - Aliases: aliases, - } + jsonDeps[dep.Name] = buildRemoteSourceString(dep.RemoteSource) } return jsonDeps diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index b2e9fda18..5529e589a 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -9,14 +9,8 @@ import ( func Test_ConfigDependencies(t *testing.T) { b := []byte(`{ - "HelloWorld": { - "remoteSource": "testnet/877931736ee77cff.HelloWorld", - "aliases": { - "testnet": "877931736ee77cff", - "mainnet": "0b2a3299cc857e29" - } - } - }`) + "HelloWorld": "testnet/877931736ee77cff.HelloWorld" + }`) var jsonDependencies jsonDependencies err := json.Unmarshal(b, &jsonDependencies) @@ -30,18 +24,11 @@ func Test_ConfigDependencies(t *testing.T) { dependencyOne := dependencies.ByName("HelloWorld") assert.NotNil(t, dependencyOne) - assert.Len(t, dependencyOne.Aliases, 2) } func Test_TransformDependenciesToJSON(t *testing.T) { b := []byte(`{ - "HelloWorld": { - "remoteSource": "testnet/877931736ee77cff.HelloWorld", - "aliases": { - "mainnet": "0b2a3299cc857e29", - "testnet": "877931736ee77cff" - } - } + "HelloWorld": "testnet/877931736ee77cff.HelloWorld" }`) var jsonDependencies jsonDependencies diff --git a/flowkit/config/loader.go b/flowkit/config/loader.go index d012c2f23..6e1176bee 100644 --- a/flowkit/config/loader.go +++ b/flowkit/config/loader.go @@ -202,7 +202,6 @@ func (l *Loader) composeConfig(baseConf *Config, conf *Config) { baseConf.Contracts.AddOrUpdate(contract) } for _, dependency := range conf.Dependencies { - fmt.Println("dependency in LOADER: ", dependency.Name) baseConf.Dependencies.AddOrUpdate(dependency) } for _, deployment := range conf.Deployments { diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index e6d355119..eddc8793b 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -171,6 +171,7 @@ func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedN }, } ci.State.Dependencies().AddOrUpdate(dep) + ci.State.Contracts().AddDependencyAsContract(dep) err := ci.State.SaveDefault() if err != nil { return err From d00de7fe80fdf812d38f780e2df13a1a14be7134 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:46:17 -0800 Subject: [PATCH 31/95] Use core contracts package for alias --- flowkit/config/contract.go | 9 ++----- flowkit/config/contract_test.go | 6 +++++ internal/contracts/contractinstaller.go | 34 ++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index a2aa19a85..a3ca3481a 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -108,17 +108,12 @@ func (c *Contracts) Remove(name string) error { } // AddDependencyAsContract adds a dependency as a contract if it doesn't already exist. -func (c *Contracts) AddDependencyAsContract(dependency Dependency) { +func (c *Contracts) AddDependencyAsContract(dependency Dependency, aliases []Alias) { fmt.Printf("Adding dependency as contract: %s\n", dependency.Name) contract := Contract{ Name: dependency.Name, Location: fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName), - Aliases: Aliases{ - Alias{ - Network: dependency.RemoteSource.NetworkName, - Address: dependency.RemoteSource.Address, - }, - }, + Aliases: aliases, } if _, err := c.ByName(contract.Name); err != nil { diff --git a/flowkit/config/contract_test.go b/flowkit/config/contract_test.go index a366104ae..2a4f1c7df 100644 --- a/flowkit/config/contract_test.go +++ b/flowkit/config/contract_test.go @@ -100,6 +100,11 @@ func TestContracts_AddDependencyAsContract(t *testing.T) { Address: flow.HexToAddress("0x0000000000abcdef"), ContractName: "TestContract", }, + }, []Alias{ + Alias{ + Network: "testnet", + Address: flow.HexToAddress("0x0000000000abcdef"), + }, }) assert.Len(t, contracts, 1) @@ -107,4 +112,5 @@ func TestContracts_AddDependencyAsContract(t *testing.T) { contract, err := contracts.ByName("testcontract") assert.NoError(t, err) assert.Equal(t, "imports/0000000000abcdef/TestContract", contract.Location) + assert.Len(t, contract.Aliases, 1) } diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index eddc8793b..42093ec44 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -3,6 +3,9 @@ package contracts import ( "fmt" + "github.com/onflow/flow-go/fvm/systemcontracts" + "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" @@ -161,6 +164,12 @@ func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assi return nil } +var networkToChainID = map[string]flow.ChainID{ + "emulator": flow.Emulator, + "testnet": flow.Testnet, + "mainnet": flow.Mainnet, +} + func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, @@ -170,8 +179,31 @@ func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedN ContractName: contractName, }, } + + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + coreContracts := sc.All() + + var aliases []config.Alias + + for _, coreContract := range coreContracts { + if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { + aliases = append(aliases, config.Alias{ + Network: networkName, + Address: flowsdk.HexToAddress(contractAddress), + }) + } + } + + // If no core contract match, then use the address in remoteSource as alias + if len(aliases) == 0 { + aliases = append(aliases, config.Alias{ + Network: dep.RemoteSource.NetworkName, + Address: dep.RemoteSource.Address, + }) + } + ci.State.Dependencies().AddOrUpdate(dep) - ci.State.Contracts().AddDependencyAsContract(dep) + ci.State.Contracts().AddDependencyAsContract(dep, aliases) err := ci.State.SaveDefault() if err != nil { return err From a87de8d3bf90f559d6c1ecfc217bdf3519d301df Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:58:52 -0800 Subject: [PATCH 32/95] Get aliases for core contracts across all networks --- internal/contracts/contractinstaller.go | 59 ++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 42093ec44..8ad83d9b6 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -170,6 +170,32 @@ var networkToChainID = map[string]flow.ChainID{ "mainnet": flow.Mainnet, } +func isCoreContract(networkName, contractName, contractAddress string) bool { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + coreContracts := sc.All() + + for _, coreContract := range coreContracts { + if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { + return true + } + } + + return false +} + +func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + coreContracts := sc.All() + + for _, coreContract := range coreContracts { + if coreContract.Name == contractName { + return &coreContract + } + } + + return nil +} + func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, @@ -180,18 +206,37 @@ func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedN }, } - sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - coreContracts := sc.All() - var aliases []config.Alias - for _, coreContract := range coreContracts { - if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { + // If core contract found by name and address matches, then use all core contract aliases across networks + if isCoreContract(networkName, contractName, contractAddress) { + emulatorCoreContract := getCoreContractByName("emulator", contractName) + + if emulatorCoreContract != nil { + aliases = append(aliases, config.Alias{ + Network: "emulator", + Address: flowsdk.HexToAddress(emulatorCoreContract.Address.String()), + }) + } + + testnetCoreContract := getCoreContractByName("testnet", contractName) + + if testnetCoreContract != nil { aliases = append(aliases, config.Alias{ - Network: networkName, - Address: flowsdk.HexToAddress(contractAddress), + Network: "testnet", + Address: flowsdk.HexToAddress(testnetCoreContract.Address.String()), }) } + + mainnetCoreContract := getCoreContractByName("mainnet", contractName) + + if mainnetCoreContract != nil { + aliases = append(aliases, config.Alias{ + Network: "mainnet", + Address: flowsdk.HexToAddress(mainnetCoreContract.Address.String()), + }) + } + } // If no core contract match, then use the address in remoteSource as alias From a2c5c2c07fb0a17f86c6a53fcd2c4b0e52eb58cc Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:18:05 -0800 Subject: [PATCH 33/95] Refactor the way aliases are applied across networks --- internal/contracts/contractinstaller.go | 51 +++++++++---------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 8ad83d9b6..7d1cef2f0 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -164,10 +164,16 @@ func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assi return nil } +const ( + NetworkEmulator = "emulator" + NetworkTestnet = "testnet" + NetworkMainnet = "mainnet" +) + var networkToChainID = map[string]flow.ChainID{ - "emulator": flow.Emulator, - "testnet": flow.Testnet, - "mainnet": flow.Mainnet, + NetworkEmulator: flow.Emulator, + NetworkTestnet: flow.Testnet, + NetworkMainnet: flow.Mainnet, } func isCoreContract(networkName, contractName, contractAddress string) bool { @@ -185,11 +191,10 @@ func isCoreContract(networkName, contractName, contractAddress string) bool { func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - coreContracts := sc.All() - for _, coreContract := range coreContracts { + for i, coreContract := range sc.All() { if coreContract.Name == contractName { - return &coreContract + return &sc.All()[i] } } @@ -210,33 +215,15 @@ func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedN // If core contract found by name and address matches, then use all core contract aliases across networks if isCoreContract(networkName, contractName, contractAddress) { - emulatorCoreContract := getCoreContractByName("emulator", contractName) - - if emulatorCoreContract != nil { - aliases = append(aliases, config.Alias{ - Network: "emulator", - Address: flowsdk.HexToAddress(emulatorCoreContract.Address.String()), - }) - } - - testnetCoreContract := getCoreContractByName("testnet", contractName) - - if testnetCoreContract != nil { - aliases = append(aliases, config.Alias{ - Network: "testnet", - Address: flowsdk.HexToAddress(testnetCoreContract.Address.String()), - }) - } - - mainnetCoreContract := getCoreContractByName("mainnet", contractName) - - if mainnetCoreContract != nil { - aliases = append(aliases, config.Alias{ - Network: "mainnet", - Address: flowsdk.HexToAddress(mainnetCoreContract.Address.String()), - }) + for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { + coreContract := getCoreContractByName(networkStr, contractName) + if coreContract != nil { + aliases = append(aliases, config.Alias{ + Network: networkStr, + Address: flowsdk.HexToAddress(coreContract.Address.String()), + }) + } } - } // If no core contract match, then use the address in remoteSource as alias From 3ff696ddc93297e2455ba588fa1ba67d7f268b09 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:19:07 -0800 Subject: [PATCH 34/95] Remove comment --- internal/contracts/contractinstaller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index 7d1cef2f0..a337badfc 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -71,7 +71,6 @@ func (ci *ContractInstaller) add(depRemoteSource, customName string) error { var name string if customName != "" { - fmt.Printf("Using custom name: %s\n", customName) name = customName } else { name = depContractName From 74ac1663f0f290931ded3437311d4a1fcaa37f26 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:32:50 -0800 Subject: [PATCH 35/95] Remove print --- flowkit/config/dependency.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 18e8fd162..dfaf2fdf0 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -8,8 +8,6 @@ import ( ) func ParseRemoteSourceString(s string) (network, address, contractName string, err error) { - fmt.Printf("Parsing: %s\n", s) - parts := strings.Split(s, "/") if len(parts) != 2 { return "", "", "", fmt.Errorf("invalid format") From 0d52b949a3cbb48d1a37dbc7e8c678b7c65147e3 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:12:03 -0800 Subject: [PATCH 36/95] Switch dependency string format --- flowkit/config/dependency.go | 6 +++--- flowkit/config/json/dependency.go | 2 +- flowkit/config/json/dependency_test.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index dfaf2fdf0..33b5b6e5d 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -8,15 +8,15 @@ import ( ) func ParseRemoteSourceString(s string) (network, address, contractName string, err error) { - parts := strings.Split(s, "/") + parts := strings.Split(s, "://") if len(parts) != 2 { - return "", "", "", fmt.Errorf("invalid format") + return "", "", "", fmt.Errorf("invalid dependency source format") } network = parts[0] subParts := strings.Split(parts[1], ".") if len(subParts) != 2 { - return "", "", "", fmt.Errorf("invalid format") + return "", "", "", fmt.Errorf("invalid dependency source format") } address = subParts[0] contractName = subParts[1] diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 85cf1a7ca..7a524b5d3 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -54,7 +54,7 @@ func buildRemoteSourceString(remoteSource config.RemoteSource) string { var builder strings.Builder builder.WriteString(remoteSource.NetworkName) - builder.WriteString("/") + builder.WriteString("://") builder.WriteString(remoteSource.Address.String()) builder.WriteString(".") builder.WriteString(remoteSource.ContractName) diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index 5529e589a..2a7eff291 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -9,7 +9,7 @@ import ( func Test_ConfigDependencies(t *testing.T) { b := []byte(`{ - "HelloWorld": "testnet/877931736ee77cff.HelloWorld" + "HelloWorld": "testnet://877931736ee77cff.HelloWorld" }`) var jsonDependencies jsonDependencies @@ -28,7 +28,7 @@ func Test_ConfigDependencies(t *testing.T) { func Test_TransformDependenciesToJSON(t *testing.T) { b := []byte(`{ - "HelloWorld": "testnet/877931736ee77cff.HelloWorld" + "HelloWorld": "testnet://877931736ee77cff.HelloWorld" }`) var jsonDependencies jsonDependencies From f090ba0317ebdd747bebd2c0bfde28f938617b47 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:37:29 -0800 Subject: [PATCH 37/95] Add progress logging --- flowkit/config/contract.go | 1 - internal/contracts/add.go | 6 ++++++ internal/contracts/install.go | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index a3ca3481a..b3393176d 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -109,7 +109,6 @@ func (c *Contracts) Remove(name string) error { // AddDependencyAsContract adds a dependency as a contract if it doesn't already exist. func (c *Contracts) AddDependencyAsContract(dependency Dependency, aliases []Alias) { - fmt.Printf("Adding dependency as contract: %s\n", dependency.Name) contract := Contract{ Name: dependency.Name, Location: fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName), diff --git a/internal/contracts/add.go b/internal/contracts/add.go index 1107a4589..1b805a16e 100644 --- a/internal/contracts/add.go +++ b/internal/contracts/add.go @@ -32,6 +32,9 @@ func add( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { + logger.StartProgress(fmt.Sprintf("Installing dependencies for %s...", args[0])) + defer logger.StopProgress() + dep := args[0] installer := NewContractInstaller(logger, state) @@ -39,5 +42,8 @@ func add( logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } + + logger.Info("✅ Dependencies installed. Check your flow.json") + return nil, nil } diff --git a/internal/contracts/install.go b/internal/contracts/install.go index a6003862e..72d150aed 100644 --- a/internal/contracts/install.go +++ b/internal/contracts/install.go @@ -29,10 +29,16 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { + logger.StartProgress("Installing dependencies from flow.json...") + defer logger.StopProgress() + installer := NewContractInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } + + logger.Info("✅ Dependencies installed. Check your flow.json") + return nil, nil } From 95bf3206bcc4ac06538d37556d9b4a2e6d22a63e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:39:11 -0800 Subject: [PATCH 38/95] Add concurrency for fetching deps --- internal/contracts/contractinstaller.go | 32 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/internal/contracts/contractinstaller.go b/internal/contracts/contractinstaller.go index a337badfc..5b3564594 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/contracts/contractinstaller.go @@ -2,6 +2,7 @@ package contracts import ( "fmt" + "sync" "github.com/onflow/flow-go/fvm/systemcontracts" "github.com/onflow/flow-go/model/flow" @@ -21,6 +22,7 @@ type ContractInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State + Mutex sync.Mutex } func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractInstaller { @@ -98,7 +100,6 @@ func (ci *ContractInstaller) processDependency(dependency config.Dependency) err } func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - ci.Logger.Info(fmt.Sprintf("Fetching dependencies for %s at %s", contractName, address)) account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %v", err) @@ -111,6 +112,9 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows return fmt.Errorf("contracts are nil for account: %s", address) } + var wg sync.WaitGroup + errCh := make(chan error, len(account.Contracts)) + for _, contract := range account.Contracts { program, err := project.NewProgram(contract, nil, "") @@ -133,21 +137,35 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows if program.HasAddressImports() { imports := program.AddressImportDeclarations() for _, imp := range imports { - importAddress := flowsdk.HexToAddress(imp.Location.String()) - contractName := imp.Identifiers[0].String() - err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) - if err != nil { - return err - } + wg.Add(1) + go func(importAddress flowsdk.Address, contractName string) { + defer wg.Done() + err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) + if err != nil { + errCh <- err + } + }(flowsdk.HexToAddress(imp.Location.String()), imp.Identifiers[0].String()) } } } } + wg.Wait() + close(errCh) + + for err := range errCh { + if err != nil { + return err + } + } + return nil } func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { + ci.Mutex.Lock() + defer ci.Mutex.Unlock() + if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) From aaf6943a9455fd71b0f8dd1f5986d27fc6bef263 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:39:36 -0800 Subject: [PATCH 39/95] Switch command name --- internal/contracts/contracts.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/contracts/contracts.go b/internal/contracts/contracts.go index 01306fa37..a26ea3537 100644 --- a/internal/contracts/contracts.go +++ b/internal/contracts/contracts.go @@ -5,10 +5,11 @@ import ( ) var Cmd = &cobra.Command{ - Use: "contracts", + Use: "dependencies", Short: "Manage contracts and dependencies", TraverseChildren: true, GroupID: "manager", + Aliases: []string{"deps"}, } func init() { From 67c37993690afd40f4260e63b5d48495826b109a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:41:23 -0800 Subject: [PATCH 40/95] Switch package name --- cmd/flow/main.go | 4 ++-- flowkit/CHANGELOG.md | 4 ++-- internal/{contracts => dependencymanager}/add.go | 2 +- .../{contracts => dependencymanager}/contractinstaller.go | 2 +- .../contracts.go => dependencymanager/dependencies.go} | 2 +- internal/{contracts => dependencymanager}/fileutils.go | 2 +- internal/{contracts => dependencymanager}/install.go | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) rename internal/{contracts => dependencymanager}/add.go (97%) rename internal/{contracts => dependencymanager}/contractinstaller.go (99%) rename internal/{contracts/contracts.go => dependencymanager/dependencies.go} (92%) rename internal/{contracts => dependencymanager}/fileutils.go (94%) rename internal/{contracts => dependencymanager}/install.go (97%) diff --git a/cmd/flow/main.go b/cmd/flow/main.go index 0ba65c605..e1f7f0146 100644 --- a/cmd/flow/main.go +++ b/cmd/flow/main.go @@ -22,7 +22,7 @@ package main import ( "os" - "github.com/onflow/flow-cli/internal/contracts" + "github.com/onflow/flow-cli/internal/dependencymanager" "github.com/spf13/cobra" @@ -89,7 +89,7 @@ func main() { cmd.AddCommand(snapshot.Cmd) cmd.AddCommand(super.FlixCmd) cmd.AddCommand(super.GenerateCommand) - cmd.AddCommand(contracts.Cmd) + cmd.AddCommand(dependencymanager.Cmd) command.InitFlags(cmd) cmd.AddGroup(&cobra.Group{ diff --git a/flowkit/CHANGELOG.md b/flowkit/CHANGELOG.md index 10ba8dac1..dba510d41 100644 --- a/flowkit/CHANGELOG.md +++ b/flowkit/CHANGELOG.md @@ -87,9 +87,9 @@ GenerateMnemonicKey(context.Context, crypto.SignatureAlgorithm, string) (crypto. DerivePrivateKeyFromMnemonic(context.Context, string, crypto.SignatureAlgorithm, string) (crypto.PrivateKey, error) -// DeployProject contracts to the Flow network or update if already exists and update is set to true. +// DeployProject dependencymanager to the Flow network or update if already exists and update is set to true. // -// Retrieve all the contracts for specified network, sort them for deployment deploy one by one and replace +// Retrieve all the dependencymanager for specified network, sort them for deployment deploy one by one and replace // the imports in the contract source, so it corresponds to the account name the contract was deployed to. DeployProject(context.Context, bool) ([]*project.Contract, error) diff --git a/internal/contracts/add.go b/internal/dependencymanager/add.go similarity index 97% rename from internal/contracts/add.go rename to internal/dependencymanager/add.go index 1b805a16e..2145642cf 100644 --- a/internal/contracts/add.go +++ b/internal/dependencymanager/add.go @@ -1,4 +1,4 @@ -package contracts +package dependencymanager import ( "fmt" diff --git a/internal/contracts/contractinstaller.go b/internal/dependencymanager/contractinstaller.go similarity index 99% rename from internal/contracts/contractinstaller.go rename to internal/dependencymanager/contractinstaller.go index 5b3564594..b5561a791 100644 --- a/internal/contracts/contractinstaller.go +++ b/internal/dependencymanager/contractinstaller.go @@ -1,4 +1,4 @@ -package contracts +package dependencymanager import ( "fmt" diff --git a/internal/contracts/contracts.go b/internal/dependencymanager/dependencies.go similarity index 92% rename from internal/contracts/contracts.go rename to internal/dependencymanager/dependencies.go index a26ea3537..6d9934af2 100644 --- a/internal/contracts/contracts.go +++ b/internal/dependencymanager/dependencies.go @@ -1,4 +1,4 @@ -package contracts +package dependencymanager import ( "github.com/spf13/cobra" diff --git a/internal/contracts/fileutils.go b/internal/dependencymanager/fileutils.go similarity index 94% rename from internal/contracts/fileutils.go rename to internal/dependencymanager/fileutils.go index 3649f1ee4..cc1a342e5 100644 --- a/internal/contracts/fileutils.go +++ b/internal/dependencymanager/fileutils.go @@ -1,4 +1,4 @@ -package contracts +package dependencymanager import ( "os" diff --git a/internal/contracts/install.go b/internal/dependencymanager/install.go similarity index 97% rename from internal/contracts/install.go rename to internal/dependencymanager/install.go index 72d150aed..a7a1fd107 100644 --- a/internal/contracts/install.go +++ b/internal/dependencymanager/install.go @@ -1,4 +1,4 @@ -package contracts +package dependencymanager import ( "fmt" From f7638fddeec677c823c32e633297c29c065ff441 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:43:08 -0800 Subject: [PATCH 41/95] Switch to DependencyManager --- internal/dependencymanager/add.go | 2 +- ...ractinstaller.go => dependencyinstaller.go} | 18 +++++++++--------- internal/dependencymanager/install.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename internal/dependencymanager/{contractinstaller.go => dependencyinstaller.go} (89%) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 2145642cf..475a214ca 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -37,7 +37,7 @@ func add( dep := args[0] - installer := NewContractInstaller(logger, state) + installer := NewDepdencyInstaller(logger, state) if err := installer.add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/internal/dependencymanager/contractinstaller.go b/internal/dependencymanager/dependencyinstaller.go similarity index 89% rename from internal/dependencymanager/contractinstaller.go rename to internal/dependencymanager/dependencyinstaller.go index b5561a791..579bf185d 100644 --- a/internal/dependencymanager/contractinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -18,14 +18,14 @@ import ( "github.com/onflow/flow-cli/flowkit/output" ) -type ContractInstaller struct { +type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State Mutex sync.Mutex } -func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractInstaller { +func NewDepdencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) @@ -47,14 +47,14 @@ func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractI config.MainnetNetwork.Name: mainnetGateway, } - return &ContractInstaller{ + return &DependencyInstaller{ Gateways: gateways, Logger: logger, State: state, } } -func (ci *ContractInstaller) install() error { +func (ci *DependencyInstaller) install() error { for _, dependency := range *ci.State.Dependencies() { if err := ci.processDependency(dependency); err != nil { ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -64,7 +64,7 @@ func (ci *ContractInstaller) install() error { return nil } -func (ci *ContractInstaller) add(depRemoteSource, customName string) error { +func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) @@ -94,12 +94,12 @@ func (ci *ContractInstaller) add(depRemoteSource, customName string) error { return nil } -func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { +func (ci *DependencyInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) } -func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { +func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %v", err) @@ -162,7 +162,7 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows return nil } -func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { +func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() @@ -218,7 +218,7 @@ func getCoreContractByName(networkName, contractName string) *systemcontracts.Sy return nil } -func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { +func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index a7a1fd107..4c0e4900c 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -32,7 +32,7 @@ func install( logger.StartProgress("Installing dependencies from flow.json...") defer logger.StopProgress() - installer := NewContractInstaller(logger, state) + installer := NewDepdencyInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From f5c88c96da0de8ae6421d69d8ff9a0120e65ed00 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:51:40 -0800 Subject: [PATCH 42/95] Don't save dependencies as contracts, just use under the hood --- flowkit/config/contract.go | 79 +++++++++++++++++-- flowkit/config/contract_test.go | 7 +- flowkit/config/json/config.go | 5 ++ flowkit/config/json/contract.go | 5 ++ flowkit/config/json/dependency.go | 5 -- flowkit/config/json/dependency_test.go | 1 + .../dependencymanager/dependencyinstaller.go | 65 +-------------- 7 files changed, 85 insertions(+), 82 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index b3393176d..679847d4c 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -20,6 +20,9 @@ package config import ( "fmt" + "github.com/onflow/flow-go/fvm/systemcontracts" + flowGo "github.com/onflow/flow-go/model/flow" + "path/filepath" "github.com/onflow/flow-go-sdk" "golang.org/x/exp/slices" @@ -27,9 +30,10 @@ import ( // Contract defines the configuration for a Cadence contract. type Contract struct { - Name string - Location string - Aliases Aliases + Name string + Location string + Aliases Aliases + IsDependency bool } // Alias defines an existing pre-deployed contract address for specific network. @@ -107,12 +111,73 @@ func (c *Contracts) Remove(name string) error { return nil } +const ( + NetworkEmulator = "emulator" + NetworkTestnet = "testnet" + NetworkMainnet = "mainnet" +) + +var networkToChainID = map[string]flowGo.ChainID{ + NetworkEmulator: flowGo.Emulator, + NetworkTestnet: flowGo.Testnet, + NetworkMainnet: flowGo.Mainnet, +} + +func isCoreContract(networkName, contractName, contractAddress string) bool { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + coreContracts := sc.All() + + for _, coreContract := range coreContracts { + if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { + return true + } + } + + return false +} + +func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + + for i, coreContract := range sc.All() { + if coreContract.Name == contractName { + return &sc.All()[i] + } + } + + return nil +} + // AddDependencyAsContract adds a dependency as a contract if it doesn't already exist. -func (c *Contracts) AddDependencyAsContract(dependency Dependency, aliases []Alias) { +func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName string) { + var aliases []Alias + + // If core contract found by name and address matches, then use all core contract aliases across networks + if isCoreContract(networkName, dependency.RemoteSource.ContractName, dependency.RemoteSource.Address.String()) { + for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { + coreContract := getCoreContractByName(networkStr, dependency.RemoteSource.ContractName) + if coreContract != nil { + aliases = append(aliases, Alias{ + Network: networkStr, + Address: flow.HexToAddress(coreContract.Address.String()), + }) + } + } + } + + // If no core contract match, then use the address in remoteSource as alias + if len(aliases) == 0 { + aliases = append(aliases, Alias{ + Network: dependency.RemoteSource.NetworkName, + Address: dependency.RemoteSource.Address, + }) + } + contract := Contract{ - Name: dependency.Name, - Location: fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName), - Aliases: aliases, + Name: dependency.Name, + Location: filepath.ToSlash(fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), + Aliases: aliases, + IsDependency: true, } if _, err := c.ByName(contract.Name); err != nil { diff --git a/flowkit/config/contract_test.go b/flowkit/config/contract_test.go index 2a4f1c7df..9854768c9 100644 --- a/flowkit/config/contract_test.go +++ b/flowkit/config/contract_test.go @@ -100,12 +100,7 @@ func TestContracts_AddDependencyAsContract(t *testing.T) { Address: flow.HexToAddress("0x0000000000abcdef"), ContractName: "TestContract", }, - }, []Alias{ - Alias{ - Network: "testnet", - Address: flow.HexToAddress("0x0000000000abcdef"), - }, - }) + }, "testnet") assert.Len(t, contracts, 1) diff --git a/flowkit/config/json/config.go b/flowkit/config/json/config.go index 2ad3b83bb..5241de598 100644 --- a/flowkit/config/json/config.go +++ b/flowkit/config/json/config.go @@ -75,6 +75,11 @@ func (j *jsonConfig) transformToConfig() (*config.Config, error) { Deployments: deployments, } + // Add dependencies as contracts so they can be used in the project just like any other contract. + for _, dep := range dependencies { + conf.Contracts.AddDependencyAsContract(dep, dep.RemoteSource.NetworkName) + } + return conf, nil } diff --git a/flowkit/config/json/contract.go b/flowkit/config/json/contract.go index b1a12b6b1..0cc90a160 100644 --- a/flowkit/config/json/contract.go +++ b/flowkit/config/json/contract.go @@ -68,6 +68,11 @@ func transformContractsToJSON(contracts config.Contracts) jsonContracts { jsonContracts := jsonContracts{} for _, c := range contracts { + // If it's a dependency, skip. These are used under the hood and should not be saved. + if c.IsDependency { + continue + } + // if simple case if !c.IsAliased() { jsonContracts[c.Name] = jsonContract{ diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 7a524b5d3..613f6f494 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -9,11 +9,6 @@ import ( "github.com/onflow/flow-cli/flowkit/config" ) -// type dependency struct { -// RemoteSource string `json:"remoteSource"` -// } -// -// type jsonDependencies map[string]dependency type jsonDependencies map[string]string func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index 2a7eff291..7942e0e07 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -22,6 +22,7 @@ func Test_ConfigDependencies(t *testing.T) { assert.Len(t, dependencies, 1) dependencyOne := dependencies.ByName("HelloWorld") + assert.NotNil(t, dependencyOne) assert.NotNil(t, dependencyOne) } diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 579bf185d..2ecc5e1b4 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -4,9 +4,6 @@ import ( "fmt" "sync" - "github.com/onflow/flow-go/fvm/systemcontracts" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" @@ -181,43 +178,6 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return nil } -const ( - NetworkEmulator = "emulator" - NetworkTestnet = "testnet" - NetworkMainnet = "mainnet" -) - -var networkToChainID = map[string]flow.ChainID{ - NetworkEmulator: flow.Emulator, - NetworkTestnet: flow.Testnet, - NetworkMainnet: flow.Mainnet, -} - -func isCoreContract(networkName, contractName, contractAddress string) bool { - sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - coreContracts := sc.All() - - for _, coreContract := range coreContracts { - if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { - return true - } - } - - return false -} - -func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { - sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - - for i, coreContract := range sc.All() { - if coreContract.Name == contractName { - return &sc.All()[i] - } - } - - return nil -} - func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, @@ -228,31 +188,8 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne }, } - var aliases []config.Alias - - // If core contract found by name and address matches, then use all core contract aliases across networks - if isCoreContract(networkName, contractName, contractAddress) { - for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { - coreContract := getCoreContractByName(networkStr, contractName) - if coreContract != nil { - aliases = append(aliases, config.Alias{ - Network: networkStr, - Address: flowsdk.HexToAddress(coreContract.Address.String()), - }) - } - } - } - - // If no core contract match, then use the address in remoteSource as alias - if len(aliases) == 0 { - aliases = append(aliases, config.Alias{ - Network: dep.RemoteSource.NetworkName, - Address: dep.RemoteSource.Address, - }) - } - ci.State.Dependencies().AddOrUpdate(dep) - ci.State.Contracts().AddDependencyAsContract(dep, aliases) + ci.State.Contracts().AddDependencyAsContract(dep, networkName) err := ci.State.SaveDefault() if err != nil { return err From 1905d1a403a90673096116c941314001b1cf8ae5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:23:28 -0800 Subject: [PATCH 43/95] Change to extended syntax --- flowkit/config/contract.go | 12 ++ flowkit/config/dependency.go | 1 + flowkit/config/json/config.go | 2 +- flowkit/config/json/dependency.go | 170 ++++++++++++++++++++++--- flowkit/config/json/dependency_test.go | 16 ++- 5 files changed, 183 insertions(+), 18 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 679847d4c..7a6db7727 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -163,6 +163,8 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s }) } } + } else { + aliases = append(aliases, dependency.Aliases...) } // If no core contract match, then use the address in remoteSource as alias @@ -184,3 +186,13 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s c.AddOrUpdate(contract) } } + +func (c *Contracts) DependencyContractByName(name string) *Contract { + for i, contract := range *c { + if contract.Name == name && contract.IsDependency { + return &(*c)[i] + } + } + + return nil +} diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 33b5b6e5d..dab279feb 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -33,6 +33,7 @@ type RemoteSource struct { type Dependency struct { Name string RemoteSource RemoteSource + Aliases Aliases } type Dependencies []Dependency diff --git a/flowkit/config/json/config.go b/flowkit/config/json/config.go index 5241de598..bc1079772 100644 --- a/flowkit/config/json/config.go +++ b/flowkit/config/json/config.go @@ -87,7 +87,7 @@ func transformConfigToJSON(config *config.Config) jsonConfig { return jsonConfig{ Emulators: transformEmulatorsToJSON(config.Emulators), Contracts: transformContractsToJSON(config.Contracts), - Dependencies: transformDependenciesToJSON(config.Dependencies), + Dependencies: transformDependenciesToJSON(config.Dependencies, config.Contracts), Networks: transformNetworksToJSON(config.Networks), Accounts: transformAccountsToJSON(config.Accounts), Deployments: transformDeploymentsToJSON(config.Deployments), diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 613f6f494..be75229a9 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -1,7 +1,9 @@ package json import ( + "encoding/json" "fmt" + "github.com/invopop/jsonschema" "strings" "github.com/onflow/flow-go-sdk" @@ -9,24 +11,53 @@ import ( "github.com/onflow/flow-cli/flowkit/config" ) -type jsonDependencies map[string]string +//type jsonDependencies map[string]string + +type jsonDependencies map[string]jsonDependency func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { deps := make(config.Dependencies, 0) - for dependencyName, dependencySource := range j { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependencySource) - if err != nil { - return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) - } + for dependencyName, dependency := range j { + var dep config.Dependency - dep := config.Dependency{ - Name: dependencyName, - RemoteSource: config.RemoteSource{ - NetworkName: depNetwork, - Address: flow.HexToAddress(depAddress), - ContractName: depContractName, - }, + if dependency.Simple != "" { + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependency.Simple) + if err != nil { + return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) + } + + dep = config.Dependency{ + Name: dependencyName, + RemoteSource: config.RemoteSource{ + NetworkName: depNetwork, + Address: flow.HexToAddress(depAddress), + ContractName: depContractName, + }, + } + } else { + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependency.Extended.RemoteSource) + if err != nil { + return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) + } + + dep = config.Dependency{ + Name: dependencyName, + RemoteSource: config.RemoteSource{ + NetworkName: depNetwork, + Address: flow.HexToAddress(depAddress), + ContractName: depContractName, + }, + } + + for network, alias := range dependency.Extended.Aliases { + address := flow.HexToAddress(alias) + if address == flow.EmptyAddress { + return nil, fmt.Errorf("invalid alias address for a contract") + } + + dep.Aliases.Add(network, address) + } } deps = append(deps, dep) @@ -35,11 +66,61 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { return deps, nil } -func transformDependenciesToJSON(configDependencies config.Dependencies) jsonDependencies { +func transformDependenciesToJSON(configDependencies config.Dependencies, configContracts config.Contracts) jsonDependencies { jsonDeps := jsonDependencies{} for _, dep := range configDependencies { - jsonDeps[dep.Name] = buildRemoteSourceString(dep.RemoteSource) + //jsonDeps[dep.Name] = buildRemoteSourceString(dep.RemoteSource) + //if dep.RemoteSource.Address != flow.EmptyAddress { + // jsonDeps[dep.Name] = jsonDependency{ + // Simple: buildRemoteSourceString(dep.RemoteSource), + // } + //} else { + // // TODO + // // check if we already created for this name then add or create + // aliases := make(map[string]string) + // for _, alias := range dep.Aliases { + // aliases[alias.Network] = alias.Address.String() + // } + // + // jsonDeps[dep.Name] = jsonDependency{ + // Extended: jsonDependencyExtended{ + // RemoteSource: fmt.Sprintf("%s://%s.%s", dep.RemoteSource.NetworkName, dep.RemoteSource.Address.String(), dep.RemoteSource.ContractName), + // Aliases: dep.Aliases, + // }, + // } + //} + + //aliases := make(map[string]string) + //for _, alias := range dep.Aliases { + // aliases[alias.Network] = alias.Address.String() + //} + // + //jsonDeps[dep.Name] = jsonDependency{ + // Extended: jsonDependencyExtended{ + // RemoteSource: fmt.Sprintf("%s://%s.%s", dep.RemoteSource.NetworkName, dep.RemoteSource.Address.String(), dep.RemoteSource.ContractName), + // Aliases: dep.Aliases, + // }, + //} + + // just always output extended? + // do you look for contract name add address to match + + aliases := make(map[string]string) + + depContract := configContracts.DependencyContractByName(dep.Name) + if depContract != nil { + for _, alias := range depContract.Aliases { + aliases[alias.Network] = alias.Address.String() + } + } + + jsonDeps[dep.Name] = jsonDependency{ + Extended: jsonDependencyExtended{ + RemoteSource: buildRemoteSourceString(dep.RemoteSource), + Aliases: aliases, + }, + } } return jsonDeps @@ -56,3 +137,62 @@ func buildRemoteSourceString(remoteSource config.RemoteSource) string { return builder.String() } + +// jsonDependencyExtended for json parsing advanced config. +type jsonDependencyExtended struct { + RemoteSource string `json:"remoteSource"` + Aliases map[string]string `json:"aliases"` +} + +// jsonDependency structure for json parsing. +type jsonDependency struct { + Simple string + Extended jsonDependencyExtended +} + +func (j *jsonDependency) UnmarshalJSON(b []byte) error { + var remoteSource string + var extendedFormat jsonDependencyExtended + + // simple + err := json.Unmarshal(b, &remoteSource) + if err == nil { + j.Simple = remoteSource //filepath.FromSlash(remoteSource) + return nil + } + + // advanced + err = json.Unmarshal(b, &extendedFormat) + if err == nil { + j.Extended = extendedFormat + //j.Extended.RemoteSource = filepath.FromSlash(j.Extended.RemoteSource) + } else { + return err + } + + return nil +} + +func (j jsonDependency) MarshalJSON() ([]byte, error) { + if j.Simple != "" { + return json.Marshal(j.Simple) + } else { + return json.Marshal(j.Extended) + } +} + +func (j jsonDependency) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + { + Type: "string", + }, + { + Ref: "#/$defs/jsonDependencyExtended", + }, + }, + Definitions: map[string]*jsonschema.Schema{ + "jsonDependencyExtended": jsonschema.Reflect(jsonDependencyExtended{}), + }, + } +} diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index 7942e0e07..a876b8ab1 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -32,15 +32,27 @@ func Test_TransformDependenciesToJSON(t *testing.T) { "HelloWorld": "testnet://877931736ee77cff.HelloWorld" }`) + bOut := []byte(`{ + "HelloWorld": { + "remoteSource": "testnet://877931736ee77cff.HelloWorld", + "aliases": {} + } + }`) + + var jsonContracts jsonContracts + errContracts := json.Unmarshal(b, &jsonContracts) + assert.NoError(t, errContracts) + var jsonDependencies jsonDependencies err := json.Unmarshal(b, &jsonDependencies) assert.NoError(t, err) + contracts, err := jsonContracts.transformToConfig() dependencies, err := jsonDependencies.transformToConfig() assert.NoError(t, err) - j := transformDependenciesToJSON(dependencies) + j := transformDependenciesToJSON(dependencies, contracts) x, _ := json.Marshal(j) - assert.Equal(t, cleanSpecialChars(b), cleanSpecialChars(x)) + assert.Equal(t, cleanSpecialChars(bOut), cleanSpecialChars(x)) } From f790b44d3c47d7495747b1824d16e9fd2ed616c7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:56:31 -0800 Subject: [PATCH 44/95] Remove commented out code --- flowkit/config/json/dependency.go | 37 ------------------------------- 1 file changed, 37 deletions(-) diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index be75229a9..f2e04b465 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -70,42 +70,6 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC jsonDeps := jsonDependencies{} for _, dep := range configDependencies { - //jsonDeps[dep.Name] = buildRemoteSourceString(dep.RemoteSource) - //if dep.RemoteSource.Address != flow.EmptyAddress { - // jsonDeps[dep.Name] = jsonDependency{ - // Simple: buildRemoteSourceString(dep.RemoteSource), - // } - //} else { - // // TODO - // // check if we already created for this name then add or create - // aliases := make(map[string]string) - // for _, alias := range dep.Aliases { - // aliases[alias.Network] = alias.Address.String() - // } - // - // jsonDeps[dep.Name] = jsonDependency{ - // Extended: jsonDependencyExtended{ - // RemoteSource: fmt.Sprintf("%s://%s.%s", dep.RemoteSource.NetworkName, dep.RemoteSource.Address.String(), dep.RemoteSource.ContractName), - // Aliases: dep.Aliases, - // }, - // } - //} - - //aliases := make(map[string]string) - //for _, alias := range dep.Aliases { - // aliases[alias.Network] = alias.Address.String() - //} - // - //jsonDeps[dep.Name] = jsonDependency{ - // Extended: jsonDependencyExtended{ - // RemoteSource: fmt.Sprintf("%s://%s.%s", dep.RemoteSource.NetworkName, dep.RemoteSource.Address.String(), dep.RemoteSource.ContractName), - // Aliases: dep.Aliases, - // }, - //} - - // just always output extended? - // do you look for contract name add address to match - aliases := make(map[string]string) depContract := configContracts.DependencyContractByName(dep.Name) @@ -165,7 +129,6 @@ func (j *jsonDependency) UnmarshalJSON(b []byte) error { err = json.Unmarshal(b, &extendedFormat) if err == nil { j.Extended = extendedFormat - //j.Extended.RemoteSource = filepath.FromSlash(j.Extended.RemoteSource) } else { return err } From 7ad3ab398ad120d93958a6e78d5da2ba0381753f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:08:38 -0800 Subject: [PATCH 45/95] Remove comment code --- flowkit/config/json/dependency.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index f2e04b465..7f9191869 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -11,8 +11,6 @@ import ( "github.com/onflow/flow-cli/flowkit/config" ) -//type jsonDependencies map[string]string - type jsonDependencies map[string]jsonDependency func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { @@ -121,7 +119,7 @@ func (j *jsonDependency) UnmarshalJSON(b []byte) error { // simple err := json.Unmarshal(b, &remoteSource) if err == nil { - j.Simple = remoteSource //filepath.FromSlash(remoteSource) + j.Simple = remoteSource return nil } From 2e42ea2e0dafa15dad14d5a40d2f3fc36dcdbdf1 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:50:57 -0800 Subject: [PATCH 46/95] Add license headers --- internal/dependencymanager/add.go | 18 ++++++++++++++++++ internal/dependencymanager/dependencies.go | 18 ++++++++++++++++++ .../dependencymanager/dependencyinstaller.go | 18 ++++++++++++++++++ internal/dependencymanager/fileutils.go | 18 ++++++++++++++++++ internal/dependencymanager/install.go | 18 ++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 475a214ca..81ed39db1 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/internal/dependencymanager/dependencies.go b/internal/dependencymanager/dependencies.go index 6d9934af2..7175b7e9b 100644 --- a/internal/dependencymanager/dependencies.go +++ b/internal/dependencymanager/dependencies.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 2ecc5e1b4..4449857c9 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/internal/dependencymanager/fileutils.go b/internal/dependencymanager/fileutils.go index cc1a342e5..485dc57ba 100644 --- a/internal/dependencymanager/fileutils.go +++ b/internal/dependencymanager/fileutils.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 4c0e4900c..8045818a6 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( From 017dea17700b5fd5436fe039b015cba6be18f015 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:59:58 -0800 Subject: [PATCH 47/95] Add license headers --- flowkit/config/dependency.go | 18 ++++++++++++++++++ flowkit/config/dependency_test.go | 18 ++++++++++++++++++ flowkit/config/json/dependency.go | 18 ++++++++++++++++++ flowkit/config/json/dependency_test.go | 18 ++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index dab279feb..2c19bacb6 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package config import ( diff --git a/flowkit/config/dependency_test.go b/flowkit/config/dependency_test.go index 33482d449..b3f00499f 100644 --- a/flowkit/config/dependency_test.go +++ b/flowkit/config/dependency_test.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package config import ( diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 7f9191869..ff78bbc1d 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package json import ( diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index a876b8ab1..5b57c86cb 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package json import ( From 64cb973d38f5e1bb5bdbae44b1fc46b9162c85e1 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:34:29 -0800 Subject: [PATCH 48/95] Fix schema --- flowkit/schema.json | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/flowkit/schema.json b/flowkit/schema.json index 2c4634b03..c29416eaf 100644 --- a/flowkit/schema.json +++ b/flowkit/schema.json @@ -217,11 +217,42 @@ "jsonDependencies": { "patternProperties": { ".*": { - "$ref": "#/$defs/jsonDependencies" + "$ref": "#/$defs/jsonDependency" } }, "type": "object" }, + "jsonDependency": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/jsonDependencyExtended" + } + ] + }, + "jsonDependencyExtended": { + "properties": { + "remoteSource": { + "type": "string" + }, + "aliases": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "remoteSource", + "aliases" + ] + }, "jsonDeployment": { "patternProperties": { ".*": { From e6340a5cf9fa342b83cf047928b5a5e760c0353d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:40:56 -0800 Subject: [PATCH 49/95] Fix golint --- flowkit/config/contract.go | 3 ++- flowkit/config/json/dependency.go | 3 ++- flowkit/mocks/Services.go | 1 + internal/dependencymanager/add.go | 3 ++- internal/dependencymanager/dependencyinstaller.go | 3 ++- internal/dependencymanager/install.go | 3 ++- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 7a6db7727..7b78f3c6f 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -20,9 +20,10 @@ package config import ( "fmt" + "path/filepath" + "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" - "path/filepath" "github.com/onflow/flow-go-sdk" "golang.org/x/exp/slices" diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index ff78bbc1d..a6f220edd 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -21,9 +21,10 @@ package json import ( "encoding/json" "fmt" - "github.com/invopop/jsonschema" "strings" + "github.com/invopop/jsonschema" + "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-cli/flowkit/config" diff --git a/flowkit/mocks/Services.go b/flowkit/mocks/Services.go index d78805928..7839bf22b 100644 --- a/flowkit/mocks/Services.go +++ b/flowkit/mocks/Services.go @@ -4,6 +4,7 @@ package mocks import ( cadence "github.com/onflow/cadence" + accounts "github.com/onflow/flow-cli/flowkit/accounts" config "github.com/onflow/flow-cli/flowkit/config" diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 81ed39db1..bd237ad70 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -21,10 +21,11 @@ package dependencymanager import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" - "github.com/spf13/cobra" ) type addFlagsCollection struct { diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 4449857c9..38ae18745 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -26,9 +26,10 @@ import ( "github.com/onflow/flow-cli/flowkit/project" - "github.com/onflow/flow-cli/flowkit/config" flowsdk "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" ) diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 8045818a6..0c132ea53 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -21,10 +21,11 @@ package dependencymanager import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" - "github.com/spf13/cobra" ) type installFlagsCollection struct{} From 5202dfedca6ca2ee8250f368139ebe9bf6dc4e04 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:02:36 -0800 Subject: [PATCH 50/95] Move import conversion to handleFoundContract --- internal/dependencymanager/dependencyinstaller.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 38ae18745..c16396841 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -144,9 +144,8 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { - program.ConvertImports() - if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, string(program.DevelopmentCode())); err != nil { + if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } @@ -178,10 +177,13 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } -func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { +func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() + program.ConvertImports() + contractData := string(program.DevelopmentCode()) + if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) From adeeaf1b4f05fb4c2e0cf0c68158260e83eefeae Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:49:46 -0800 Subject: [PATCH 51/95] Add version hash to dependency --- flowkit/config/dependency.go | 1 + flowkit/config/json/dependency.go | 5 +- flowkit/config/json/dependency_test.go | 1 + flowkit/gateway/mocks/Gateway.go | 70 ++++++++++++++- flowkit/mocks/Services.go | 87 ++++++++++++++++++- flowkit/schema.json | 4 + .../dependencymanager/dependencyinstaller.go | 11 ++- 7 files changed, 173 insertions(+), 6 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 2c19bacb6..2a7f82c8e 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -51,6 +51,7 @@ type RemoteSource struct { type Dependency struct { Name string RemoteSource RemoteSource + Version string Aliases Aliases } diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index a6f220edd..46cc27822 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -59,7 +59,8 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { } dep = config.Dependency{ - Name: dependencyName, + Name: dependencyName, + Version: dependency.Extended.Version, RemoteSource: config.RemoteSource{ NetworkName: depNetwork, Address: flow.HexToAddress(depAddress), @@ -99,6 +100,7 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC jsonDeps[dep.Name] = jsonDependency{ Extended: jsonDependencyExtended{ RemoteSource: buildRemoteSourceString(dep.RemoteSource), + Version: dep.Version, Aliases: aliases, }, } @@ -122,6 +124,7 @@ func buildRemoteSourceString(remoteSource config.RemoteSource) string { // jsonDependencyExtended for json parsing advanced config. type jsonDependencyExtended struct { RemoteSource string `json:"remoteSource"` + Version string `json:"version"` Aliases map[string]string `json:"aliases"` } diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index 5b57c86cb..a1ce35130 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -53,6 +53,7 @@ func Test_TransformDependenciesToJSON(t *testing.T) { bOut := []byte(`{ "HelloWorld": { "remoteSource": "testnet://877931736ee77cff.HelloWorld", + "version": "", "aliases": {} } }`) diff --git a/flowkit/gateway/mocks/Gateway.go b/flowkit/gateway/mocks/Gateway.go index 5fd4ba569..73453438e 100644 --- a/flowkit/gateway/mocks/Gateway.go +++ b/flowkit/gateway/mocks/Gateway.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.36.0. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Gateway struct { func (_m *Gateway) ExecuteScript(_a0 []byte, _a1 []cadence.Value) (cadence.Value, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for ExecuteScript") + } + var r0 cadence.Value var r1 error if rf, ok := ret.Get(0).(func([]byte, []cadence.Value) (cadence.Value, error)); ok { @@ -44,6 +48,10 @@ func (_m *Gateway) ExecuteScript(_a0 []byte, _a1 []cadence.Value) (cadence.Value func (_m *Gateway) ExecuteScriptAtHeight(_a0 []byte, _a1 []cadence.Value, _a2 uint64) (cadence.Value, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for ExecuteScriptAtHeight") + } + var r0 cadence.Value var r1 error if rf, ok := ret.Get(0).(func([]byte, []cadence.Value, uint64) (cadence.Value, error)); ok { @@ -70,6 +78,10 @@ func (_m *Gateway) ExecuteScriptAtHeight(_a0 []byte, _a1 []cadence.Value, _a2 ui func (_m *Gateway) ExecuteScriptAtID(_a0 []byte, _a1 []cadence.Value, _a2 flow.Identifier) (cadence.Value, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for ExecuteScriptAtID") + } + var r0 cadence.Value var r1 error if rf, ok := ret.Get(0).(func([]byte, []cadence.Value, flow.Identifier) (cadence.Value, error)); ok { @@ -96,6 +108,10 @@ func (_m *Gateway) ExecuteScriptAtID(_a0 []byte, _a1 []cadence.Value, _a2 flow.I func (_m *Gateway) GetAccount(_a0 flow.Address) (*flow.Account, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetAccount") + } + var r0 *flow.Account var r1 error if rf, ok := ret.Get(0).(func(flow.Address) (*flow.Account, error)); ok { @@ -122,6 +138,10 @@ func (_m *Gateway) GetAccount(_a0 flow.Address) (*flow.Account, error) { func (_m *Gateway) GetBlockByHeight(_a0 uint64) (*flow.Block, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetBlockByHeight") + } + var r0 *flow.Block var r1 error if rf, ok := ret.Get(0).(func(uint64) (*flow.Block, error)); ok { @@ -148,6 +168,10 @@ func (_m *Gateway) GetBlockByHeight(_a0 uint64) (*flow.Block, error) { func (_m *Gateway) GetBlockByID(_a0 flow.Identifier) (*flow.Block, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetBlockByID") + } + var r0 *flow.Block var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier) (*flow.Block, error)); ok { @@ -174,6 +198,10 @@ func (_m *Gateway) GetBlockByID(_a0 flow.Identifier) (*flow.Block, error) { func (_m *Gateway) GetCollection(_a0 flow.Identifier) (*flow.Collection, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetCollection") + } + var r0 *flow.Collection var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier) (*flow.Collection, error)); ok { @@ -200,6 +228,10 @@ func (_m *Gateway) GetCollection(_a0 flow.Identifier) (*flow.Collection, error) func (_m *Gateway) GetEvents(_a0 string, _a1 uint64, _a2 uint64) ([]flow.BlockEvents, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GetEvents") + } + var r0 []flow.BlockEvents var r1 error if rf, ok := ret.Get(0).(func(string, uint64, uint64) ([]flow.BlockEvents, error)); ok { @@ -226,6 +258,10 @@ func (_m *Gateway) GetEvents(_a0 string, _a1 uint64, _a2 uint64) ([]flow.BlockEv func (_m *Gateway) GetLatestBlock() (*flow.Block, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLatestBlock") + } + var r0 *flow.Block var r1 error if rf, ok := ret.Get(0).(func() (*flow.Block, error)); ok { @@ -252,6 +288,10 @@ func (_m *Gateway) GetLatestBlock() (*flow.Block, error) { func (_m *Gateway) GetLatestProtocolStateSnapshot() ([]byte, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLatestProtocolStateSnapshot") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func() ([]byte, error)); ok { @@ -278,6 +318,10 @@ func (_m *Gateway) GetLatestProtocolStateSnapshot() ([]byte, error) { func (_m *Gateway) GetTransaction(_a0 flow.Identifier) (*flow.Transaction, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetTransaction") + } + var r0 *flow.Transaction var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier) (*flow.Transaction, error)); ok { @@ -304,6 +348,10 @@ func (_m *Gateway) GetTransaction(_a0 flow.Identifier) (*flow.Transaction, error func (_m *Gateway) GetTransactionResult(_a0 flow.Identifier, _a1 bool) (*flow.TransactionResult, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetTransactionResult") + } + var r0 *flow.TransactionResult var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier, bool) (*flow.TransactionResult, error)); ok { @@ -330,6 +378,10 @@ func (_m *Gateway) GetTransactionResult(_a0 flow.Identifier, _a1 bool) (*flow.Tr func (_m *Gateway) GetTransactionResultsByBlockID(blockID flow.Identifier) ([]*flow.TransactionResult, error) { ret := _m.Called(blockID) + if len(ret) == 0 { + panic("no return value specified for GetTransactionResultsByBlockID") + } + var r0 []*flow.TransactionResult var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier) ([]*flow.TransactionResult, error)); ok { @@ -356,6 +408,10 @@ func (_m *Gateway) GetTransactionResultsByBlockID(blockID flow.Identifier) ([]*f func (_m *Gateway) GetTransactionsByBlockID(blockID flow.Identifier) ([]*flow.Transaction, error) { ret := _m.Called(blockID) + if len(ret) == 0 { + panic("no return value specified for GetTransactionsByBlockID") + } + var r0 []*flow.Transaction var r1 error if rf, ok := ret.Get(0).(func(flow.Identifier) ([]*flow.Transaction, error)); ok { @@ -382,6 +438,10 @@ func (_m *Gateway) GetTransactionsByBlockID(blockID flow.Identifier) ([]*flow.Tr func (_m *Gateway) Ping() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ping") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -396,6 +456,10 @@ func (_m *Gateway) Ping() error { func (_m *Gateway) SecureConnection() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SecureConnection") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -410,6 +474,10 @@ func (_m *Gateway) SecureConnection() bool { func (_m *Gateway) SendSignedTransaction(_a0 *flow.Transaction) (*flow.Transaction, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for SendSignedTransaction") + } + var r0 *flow.Transaction var r1 error if rf, ok := ret.Get(0).(func(*flow.Transaction) (*flow.Transaction, error)); ok { diff --git a/flowkit/mocks/Services.go b/flowkit/mocks/Services.go index 7839bf22b..9800ecd35 100644 --- a/flowkit/mocks/Services.go +++ b/flowkit/mocks/Services.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.36.0. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( cadence "github.com/onflow/cadence" - accounts "github.com/onflow/flow-cli/flowkit/accounts" config "github.com/onflow/flow-cli/flowkit/config" @@ -37,6 +36,10 @@ type Services struct { func (_m *Services) AddContract(_a0 context.Context, _a1 *accounts.Account, _a2 flowkit.Script, _a3 flowkit.UpdateContract) (flow.Identifier, bool, error) { ret := _m.Called(_a0, _a1, _a2, _a3) + if len(ret) == 0 { + panic("no return value specified for AddContract") + } + var r0 flow.Identifier var r1 bool var r2 error @@ -70,6 +73,10 @@ func (_m *Services) AddContract(_a0 context.Context, _a1 *accounts.Account, _a2 func (_m *Services) BuildTransaction(_a0 context.Context, _a1 transactions.AddressesRoles, _a2 int, _a3 flowkit.Script, _a4 uint64) (*transactions.Transaction, error) { ret := _m.Called(_a0, _a1, _a2, _a3, _a4) + if len(ret) == 0 { + panic("no return value specified for BuildTransaction") + } + var r0 *transactions.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, transactions.AddressesRoles, int, flowkit.Script, uint64) (*transactions.Transaction, error)); ok { @@ -96,6 +103,10 @@ func (_m *Services) BuildTransaction(_a0 context.Context, _a1 transactions.Addre func (_m *Services) CreateAccount(_a0 context.Context, _a1 *accounts.Account, _a2 []accounts.PublicKey) (*flow.Account, flow.Identifier, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for CreateAccount") + } + var r0 *flow.Account var r1 flow.Identifier var r2 error @@ -131,6 +142,10 @@ func (_m *Services) CreateAccount(_a0 context.Context, _a1 *accounts.Account, _a func (_m *Services) DeployProject(_a0 context.Context, _a1 flowkit.UpdateContract) ([]*project.Contract, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for DeployProject") + } + var r0 []*project.Contract var r1 error if rf, ok := ret.Get(0).(func(context.Context, flowkit.UpdateContract) ([]*project.Contract, error)); ok { @@ -157,6 +172,10 @@ func (_m *Services) DeployProject(_a0 context.Context, _a1 flowkit.UpdateContrac func (_m *Services) DerivePrivateKeyFromMnemonic(_a0 context.Context, _a1 string, _a2 crypto.SigningAlgorithm, _a3 string) (crypto.PrivateKey, error) { ret := _m.Called(_a0, _a1, _a2, _a3) + if len(ret) == 0 { + panic("no return value specified for DerivePrivateKeyFromMnemonic") + } + var r0 crypto.PrivateKey var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, crypto.SigningAlgorithm, string) (crypto.PrivateKey, error)); ok { @@ -183,6 +202,10 @@ func (_m *Services) DerivePrivateKeyFromMnemonic(_a0 context.Context, _a1 string func (_m *Services) ExecuteScript(_a0 context.Context, _a1 flowkit.Script, _a2 flowkit.ScriptQuery) (cadence.Value, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for ExecuteScript") + } + var r0 cadence.Value var r1 error if rf, ok := ret.Get(0).(func(context.Context, flowkit.Script, flowkit.ScriptQuery) (cadence.Value, error)); ok { @@ -209,6 +232,10 @@ func (_m *Services) ExecuteScript(_a0 context.Context, _a1 flowkit.Script, _a2 f func (_m *Services) Gateway() gateway.Gateway { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Gateway") + } + var r0 gateway.Gateway if rf, ok := ret.Get(0).(func() gateway.Gateway); ok { r0 = rf() @@ -225,6 +252,10 @@ func (_m *Services) Gateway() gateway.Gateway { func (_m *Services) GenerateKey(_a0 context.Context, _a1 crypto.SigningAlgorithm, _a2 string) (crypto.PrivateKey, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GenerateKey") + } + var r0 crypto.PrivateKey var r1 error if rf, ok := ret.Get(0).(func(context.Context, crypto.SigningAlgorithm, string) (crypto.PrivateKey, error)); ok { @@ -251,6 +282,10 @@ func (_m *Services) GenerateKey(_a0 context.Context, _a1 crypto.SigningAlgorithm func (_m *Services) GenerateMnemonicKey(_a0 context.Context, _a1 crypto.SigningAlgorithm, _a2 string) (crypto.PrivateKey, string, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GenerateMnemonicKey") + } + var r0 crypto.PrivateKey var r1 string var r2 error @@ -284,6 +319,10 @@ func (_m *Services) GenerateMnemonicKey(_a0 context.Context, _a1 crypto.SigningA func (_m *Services) GetAccount(_a0 context.Context, _a1 flow.Address) (*flow.Account, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetAccount") + } + var r0 *flow.Account var r1 error if rf, ok := ret.Get(0).(func(context.Context, flow.Address) (*flow.Account, error)); ok { @@ -310,6 +349,10 @@ func (_m *Services) GetAccount(_a0 context.Context, _a1 flow.Address) (*flow.Acc func (_m *Services) GetBlock(_a0 context.Context, _a1 flowkit.BlockQuery) (*flow.Block, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetBlock") + } + var r0 *flow.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, flowkit.BlockQuery) (*flow.Block, error)); ok { @@ -336,6 +379,10 @@ func (_m *Services) GetBlock(_a0 context.Context, _a1 flowkit.BlockQuery) (*flow func (_m *Services) GetCollection(_a0 context.Context, _a1 flow.Identifier) (*flow.Collection, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetCollection") + } + var r0 *flow.Collection var r1 error if rf, ok := ret.Get(0).(func(context.Context, flow.Identifier) (*flow.Collection, error)); ok { @@ -362,6 +409,10 @@ func (_m *Services) GetCollection(_a0 context.Context, _a1 flow.Identifier) (*fl func (_m *Services) GetEvents(_a0 context.Context, _a1 []string, _a2 uint64, _a3 uint64, _a4 *flowkit.EventWorker) ([]flow.BlockEvents, error) { ret := _m.Called(_a0, _a1, _a2, _a3, _a4) + if len(ret) == 0 { + panic("no return value specified for GetEvents") + } + var r0 []flow.BlockEvents var r1 error if rf, ok := ret.Get(0).(func(context.Context, []string, uint64, uint64, *flowkit.EventWorker) ([]flow.BlockEvents, error)); ok { @@ -388,6 +439,10 @@ func (_m *Services) GetEvents(_a0 context.Context, _a1 []string, _a2 uint64, _a3 func (_m *Services) GetTransactionByID(_a0 context.Context, _a1 flow.Identifier, _a2 bool) (*flow.Transaction, *flow.TransactionResult, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GetTransactionByID") + } + var r0 *flow.Transaction var r1 *flow.TransactionResult var r2 error @@ -423,6 +478,10 @@ func (_m *Services) GetTransactionByID(_a0 context.Context, _a1 flow.Identifier, func (_m *Services) GetTransactionsByBlockID(_a0 context.Context, _a1 flow.Identifier) ([]*flow.Transaction, []*flow.TransactionResult, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for GetTransactionsByBlockID") + } + var r0 []*flow.Transaction var r1 []*flow.TransactionResult var r2 error @@ -458,6 +517,10 @@ func (_m *Services) GetTransactionsByBlockID(_a0 context.Context, _a1 flow.Ident func (_m *Services) Network() config.Network { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Network") + } + var r0 config.Network if rf, ok := ret.Get(0).(func() config.Network); ok { r0 = rf() @@ -472,6 +535,10 @@ func (_m *Services) Network() config.Network { func (_m *Services) Ping() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ping") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -486,6 +553,10 @@ func (_m *Services) Ping() error { func (_m *Services) RemoveContract(_a0 context.Context, _a1 *accounts.Account, _a2 string) (flow.Identifier, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for RemoveContract") + } + var r0 flow.Identifier var r1 error if rf, ok := ret.Get(0).(func(context.Context, *accounts.Account, string) (flow.Identifier, error)); ok { @@ -512,6 +583,10 @@ func (_m *Services) RemoveContract(_a0 context.Context, _a1 *accounts.Account, _ func (_m *Services) SendSignedTransaction(_a0 context.Context, _a1 *transactions.Transaction) (*flow.Transaction, *flow.TransactionResult, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for SendSignedTransaction") + } + var r0 *flow.Transaction var r1 *flow.TransactionResult var r2 error @@ -547,6 +622,10 @@ func (_m *Services) SendSignedTransaction(_a0 context.Context, _a1 *transactions func (_m *Services) SendTransaction(_a0 context.Context, _a1 transactions.AccountRoles, _a2 flowkit.Script, _a3 uint64) (*flow.Transaction, *flow.TransactionResult, error) { ret := _m.Called(_a0, _a1, _a2, _a3) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 *flow.Transaction var r1 *flow.TransactionResult var r2 error @@ -587,6 +666,10 @@ func (_m *Services) SetLogger(_a0 output.Logger) { func (_m *Services) SignTransactionPayload(_a0 context.Context, _a1 *accounts.Account, _a2 []byte) (*transactions.Transaction, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for SignTransactionPayload") + } + var r0 *transactions.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, *accounts.Account, []byte) (*transactions.Transaction, error)); ok { diff --git a/flowkit/schema.json b/flowkit/schema.json index c29416eaf..eae3feeed 100644 --- a/flowkit/schema.json +++ b/flowkit/schema.json @@ -237,6 +237,9 @@ "remoteSource": { "type": "string" }, + "version": { + "type": "string" + }, "aliases": { "patternProperties": { ".*": { @@ -250,6 +253,7 @@ "type": "object", "required": [ "remoteSource", + "version", "aliases" ] }, diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index c16396841..86d76fdde 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -19,6 +19,8 @@ package dependencymanager import ( + "crypto/sha256" + "encoding/hex" "fmt" "sync" @@ -181,6 +183,10 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as ci.Mutex.Lock() defer ci.Mutex.Unlock() + hash := sha256.New() + hash.Write(program.DevelopmentCode()) + originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) + program.ConvertImports() contractData := string(program.DevelopmentCode()) @@ -190,7 +196,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - err := ci.updateState(networkName, contractAddr, assignedName, contractName) + err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err @@ -199,7 +205,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return nil } -func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { +func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ @@ -207,6 +213,7 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, }, + Version: contractHash, } ci.State.Dependencies().AddOrUpdate(dep) From 63ead15870a0c7f038c8ced755bc15d0a1a686e5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:44:06 -0800 Subject: [PATCH 52/95] Add prompt for updating out of date deps --- internal/dependencymanager/add.go | 3 +-- internal/dependencymanager/dependencyinstaller.go | 11 +++++++++++ internal/dependencymanager/install.go | 3 +-- internal/util/prompt.go | 10 ++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index bd237ad70..9a473b190 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -51,8 +51,7 @@ func add( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.StartProgress(fmt.Sprintf("Installing dependencies for %s...", args[0])) - defer logger.StopProgress() + logger.Info(fmt.Sprintf("🔄 Installing dependencies for %s...", args[0])) dep := args[0] diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 86d76fdde..3ee15180d 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -22,6 +22,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/onflow/flow-cli/internal/util" "sync" "github.com/onflow/flow-cli/flowkit/gateway" @@ -190,6 +191,16 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) + // Check version hash and prompt if different + // Ignore if no hash + dependency := ci.State.Dependencies().ByName(assignedName) + if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { + msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) + if !util.GenericBoolPrompt(msg) { + return nil + } + } + if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 0c132ea53..83a571172 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -48,8 +48,7 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.StartProgress("Installing dependencies from flow.json...") - defer logger.StopProgress() + logger.Info("🔄 Installing dependencies from flow.json...") installer := NewDepdencyInstaller(logger, state) if err := installer.install(); err != nil { diff --git a/internal/util/prompt.go b/internal/util/prompt.go index deb194d73..392aa8d34 100644 --- a/internal/util/prompt.go +++ b/internal/util/prompt.go @@ -756,3 +756,13 @@ func ScaffoldPrompt(logger output.Logger, scaffoldItems []ScaffoldItem) int { return 0 } + +func GenericBoolPrompt(msg string) bool { + prompt := promptui.Select{ + Label: msg, + Items: []string{"Yes", "No"}, + } + _, result, _ := prompt.Run() + + return result == "Yes" +} From 691813d6335723f090e40e344e07c470b44891b6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 09:29:05 -0800 Subject: [PATCH 53/95] Fix lint --- flowkit/mocks/Services.go | 1 + internal/dependencymanager/dependencyinstaller.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/flowkit/mocks/Services.go b/flowkit/mocks/Services.go index 9800ecd35..b63714420 100644 --- a/flowkit/mocks/Services.go +++ b/flowkit/mocks/Services.go @@ -4,6 +4,7 @@ package mocks import ( cadence "github.com/onflow/cadence" + accounts "github.com/onflow/flow-cli/flowkit/accounts" config "github.com/onflow/flow-cli/flowkit/config" diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 3ee15180d..c7e4eaba2 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -22,9 +22,10 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/util" "sync" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" From bb90ec93b2ae4d6acd5d044792d9cfd79a3e0d2f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:38:13 -0800 Subject: [PATCH 54/95] Error if conflict exists --- .../dependencymanager/dependencyinstaller.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index c7e4eaba2..3b53e86c0 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -22,9 +22,9 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "sync" - "github.com/onflow/flow-cli/internal/util" + "os" + "sync" "github.com/onflow/flow-cli/flowkit/gateway" @@ -192,9 +192,18 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) - // Check version hash and prompt if different - // Ignore if no hash dependency := ci.State.Dependencies().ByName(assignedName) + + // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue + if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { + ci.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) + os.Exit(0) + return nil + } + + // Check if remote source version is different from local version + // If it is, ask if they want to update + // If no hash, ignore if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) if !util.GenericBoolPrompt(msg) { From 19eab93f8034eca71df51215d14c42c08bb19fb7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 17:02:43 -0800 Subject: [PATCH 55/95] Run lint --- internal/dependencymanager/dependencyinstaller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 3b53e86c0..625f0f14e 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -22,10 +22,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/util" "os" "sync" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" From d123b768625ceacc14b61418141593a395f2e101 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:50:37 -0800 Subject: [PATCH 56/95] Fix typo --- internal/dependencymanager/add.go | 2 +- internal/dependencymanager/dependencyinstaller.go | 2 +- internal/dependencymanager/install.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 9a473b190..7cb4399d4 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -55,7 +55,7 @@ func add( dep := args[0] - installer := NewDepdencyInstaller(logger, state) + installer := NewDependencyInstaller(logger, state) if err := installer.add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 625f0f14e..1d3036c7d 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -46,7 +46,7 @@ type DependencyInstaller struct { Mutex sync.Mutex } -func NewDepdencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 83a571172..751a8a087 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -50,7 +50,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer := NewDepdencyInstaller(logger, state) + installer := NewDependencyInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 061f265f2fd20cd89eefc37e512e4eaa039d57a5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:00:32 -0800 Subject: [PATCH 57/95] Change to wrapped error when returned --- internal/dependencymanager/dependencyinstaller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 1d3036c7d..c8c3f23ac 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -123,7 +123,7 @@ func (ci *DependencyInstaller) processDependency(dependency config.Dependency) e func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { - return fmt.Errorf("failed to get account: %v", err) + return fmt.Errorf("failed to get account: %w", err) } if account == nil { return fmt.Errorf("account is nil for address: %s", address) @@ -140,18 +140,18 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo program, err := project.NewProgram(contract, nil, "") if err != nil { - return fmt.Errorf("failed to parse program: %v", err) + return fmt.Errorf("failed to parse program: %w", err) } parsedContractName, err := program.Name() if err != nil { - return fmt.Errorf("failed to parse contract name: %v", err) + return fmt.Errorf("failed to parse contract name: %w", err) } if parsedContractName == contractName { if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { - return fmt.Errorf("failed to handle found contract: %v", err) + return fmt.Errorf("failed to handle found contract: %w", err) } if program.HasAddressImports() { @@ -214,7 +214,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { - return fmt.Errorf("failed to create contract file: %v", err) + return fmt.Errorf("failed to create contract file: %w", err) } } From b92f6d87f17d5a6f1af491d307056b63f95bcd72 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:02:26 -0800 Subject: [PATCH 58/95] Add message around dep installed --- internal/dependencymanager/dependencyinstaller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index c8c3f23ac..71ea086b9 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -216,6 +216,8 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } + + ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) } err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) From d44d411bf7828a30fa36afe26ae9fc36a4268db9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:07:11 -0800 Subject: [PATCH 59/95] Add message if added to flow.json --- internal/dependencymanager/dependencyinstaller.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 71ea086b9..e659fa849 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -240,6 +240,8 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Version: contractHash, } + isNewDep := ci.State.Dependencies().ByName(dep.Name) == nil + ci.State.Dependencies().AddOrUpdate(dep) ci.State.Contracts().AddDependencyAsContract(dep, networkName) err := ci.State.SaveDefault() @@ -247,5 +249,9 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne return err } + if isNewDep { + ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) + } + return nil } From f9af4ff2320862f90f9f4cdb5b0e1591069f1878 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Wed, 17 Jan 2024 09:17:51 -0800 Subject: [PATCH 60/95] Update .gitignore Co-authored-by: Ian Pun --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9c941fa56..b8403f505 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,5 @@ git main *.pkey -# Local developement file generation +# Local development file generation folder imports \ No newline at end of file From 42da1da93318f09218be2b8c7f99b4bab599e335 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 17 Jan 2024 09:24:55 -0800 Subject: [PATCH 61/95] Remove unnecessary line --- flowkit/config/contract.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 7b78f3c6f..300cd013e 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -126,9 +126,8 @@ var networkToChainID = map[string]flowGo.ChainID{ func isCoreContract(networkName, contractName, contractAddress string) bool { sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - coreContracts := sc.All() - for _, coreContract := range coreContracts { + for _, coreContract := range sc.All() { if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { return true } From 09fbcc354bf5dcacd59c4626a6a24f8cbf61329f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 17 Jan 2024 09:25:58 -0800 Subject: [PATCH 62/95] Undo change in doc --- flowkit/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flowkit/CHANGELOG.md b/flowkit/CHANGELOG.md index dba510d41..10ba8dac1 100644 --- a/flowkit/CHANGELOG.md +++ b/flowkit/CHANGELOG.md @@ -87,9 +87,9 @@ GenerateMnemonicKey(context.Context, crypto.SignatureAlgorithm, string) (crypto. DerivePrivateKeyFromMnemonic(context.Context, string, crypto.SignatureAlgorithm, string) (crypto.PrivateKey, error) -// DeployProject dependencymanager to the Flow network or update if already exists and update is set to true. +// DeployProject contracts to the Flow network or update if already exists and update is set to true. // -// Retrieve all the dependencymanager for specified network, sort them for deployment deploy one by one and replace +// Retrieve all the contracts for specified network, sort them for deployment deploy one by one and replace // the imports in the contract source, so it corresponds to the account name the contract was deployed to. DeployProject(context.Context, bool) ([]*project.Contract, error) From 5cb565f40991b38a48de63082d1a54c7e1ad86a9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:53:43 -0800 Subject: [PATCH 63/95] Clean up name conditional --- internal/dependencymanager/dependencyinstaller.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index e659fa849..6694a7dc7 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -91,12 +91,10 @@ func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { return fmt.Errorf("error parsing remote source: %w", err) } - var name string + name := depContractName if customName != "" { name = customName - } else { - name = depContractName } dep := config.Dependency{ From a2a0b280e03f12a1d2345df33f7a7d4fc99c92e6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:49:00 -0800 Subject: [PATCH 64/95] Fix issue with hardcoded network --- internal/dependencymanager/dependencyinstaller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 6694a7dc7..d9fa1233b 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -158,7 +158,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { defer wg.Done() - err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) + err := ci.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err } From 2bd617ee5480519d16b5f893d70c90255ee57e7b Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:48:32 -0800 Subject: [PATCH 65/95] Add test for install --- flowkit/tests/resources.go | 15 ++++++- internal/dependencymanager/install_test.go | 46 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 internal/dependencymanager/install_test.go diff --git a/flowkit/tests/resources.go b/flowkit/tests/resources.go index bfeaf5128..c7f62d128 100644 --- a/flowkit/tests/resources.go +++ b/flowkit/tests/resources.go @@ -20,7 +20,6 @@ package tests import ( "fmt" - "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go-sdk" @@ -581,6 +580,20 @@ func NewAccountWithAddress(address string) *flow.Account { return account } +func NewAccountWithContracts(address string, contracts ...Resource) *flow.Account { + account := accounts.New() + + if account.Contracts == nil { + account.Contracts = make(map[string][]byte) + } + + for _, contract := range contracts { + account.Contracts[contract.Name] = contract.Source + } + + return account +} + func NewTransaction() *flow.Transaction { return transactions.New() } diff --git a/internal/dependencymanager/install_test.go b/internal/dependencymanager/install_test.go new file mode 100644 index 000000000..8306b2610 --- /dev/null +++ b/internal/dependencymanager/install_test.go @@ -0,0 +1,46 @@ +package dependencymanager + +import ( + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/flowkit/tests" + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" +) + +func TestInstallDependencies(t *testing.T) { + logger := output.NewStdoutLogger(output.NoneLog) + srv, state, _ := util.TestMocks(t) + + dep := config.Dependency{ + Name: "Hello", + RemoteSource: config.RemoteSource{ + NetworkName: "emulator", + Address: flow.HexToAddress("0000000000000001"), + ContractName: "Hello", + }, + } + + state.Dependencies().AddOrUpdate(dep) + + t.Run("Success", func(t *testing.T) { + inArgs := []string{"0x1"} + + srv.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(1).(flow.Address) + assert.Equal(t, "0000000000000001", addr.String()) + srv.GetAccount.Return(tests.NewAccountWithContracts(inArgs[0], tests.ContractHelloString), nil) + }) + + _, err := install([]string{}, command.GlobalFlags{}, logger, srv.Mock, state) + assert.NoError(t, err, "Failed to install dependencies") + + fileContent, err := state.ReaderWriter().ReadFile("imports/0000000000000001/Hello") + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} From b2a5009769d461c2253ec6220d5b8993d5e1374c Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:49:37 -0800 Subject: [PATCH 66/95] Add account address --- flowkit/tests/resources.go | 1 + 1 file changed, 1 insertion(+) diff --git a/flowkit/tests/resources.go b/flowkit/tests/resources.go index c7f62d128..e889a002e 100644 --- a/flowkit/tests/resources.go +++ b/flowkit/tests/resources.go @@ -582,6 +582,7 @@ func NewAccountWithAddress(address string) *flow.Account { func NewAccountWithContracts(address string, contracts ...Resource) *flow.Account { account := accounts.New() + account.Address = flow.HexToAddress(address) if account.Contracts == nil { account.Contracts = make(map[string][]byte) From 66e04649ee8f3db7aa7d55cb182b9af72ec940cd Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:45:31 -0800 Subject: [PATCH 67/95] Add test for install --- flowkit/state.go | 1 + .../dependencymanager/dependencyinstaller.go | 28 +++++++- .../dependencyinstaller_test.go | 68 +++++++++++++++++++ internal/dependencymanager/fileutils.go | 41 ----------- internal/dependencymanager/install_test.go | 46 ------------- 5 files changed, 95 insertions(+), 89 deletions(-) create mode 100644 internal/dependencymanager/dependencyinstaller_test.go delete mode 100644 internal/dependencymanager/fileutils.go delete mode 100644 internal/dependencymanager/install_test.go diff --git a/flowkit/state.go b/flowkit/state.go index 1b5038bdf..0f9c975a8 100644 --- a/flowkit/state.go +++ b/flowkit/state.go @@ -38,6 +38,7 @@ type ReaderWriter interface { ReadFile(source string) ([]byte, error) WriteFile(filename string, data []byte, perm os.FileMode) error MkdirAll(path string, perm os.FileMode) error + Stat(path string) (os.FileInfo, error) } // State manages the state for a Flow project. diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index d9fa1233b..79287ea9c 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -23,6 +23,7 @@ import ( "encoding/hex" "fmt" "os" + "path/filepath" "sync" "github.com/onflow/flow-cli/internal/util" @@ -180,6 +181,29 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } +func (ci *DependencyInstaller) contractFileExists(address, contractName string) bool { + path := filepath.Join("imports", address, contractName) + + _, err := ci.State.ReaderWriter().Stat(path) + + return err == nil +} + +func (ci *DependencyInstaller) createContractFile(address, contractName, data string) error { + path := filepath.Join("imports", address, contractName) + dir := filepath.Dir(path) + + if err := ci.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("error creating directories: %w", err) + } + + if err := ci.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { + return fmt.Errorf("error writing file: %w", err) + } + + return nil +} + func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() @@ -210,8 +234,8 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !contractFileExists(contractAddr, contractName) { - if err := createContractFile(contractAddr, contractName, contractData); err != nil { + if !ci.contractFileExists(contractAddr, contractName) { + if err := ci.createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go new file mode 100644 index 000000000..f4ff585d1 --- /dev/null +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -0,0 +1,68 @@ +package dependencymanager + +import ( + "fmt" + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit/gateway" + "github.com/onflow/flow-cli/flowkit/gateway/mocks" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/flowkit/tests" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" +) + +func TestDependencyInstallerInstall(t *testing.T) { + + logger := output.NewStdoutLogger(output.NoneLog) + _, state, _ := util.TestMocks(t) + + serviceAcc, _ := state.EmulatorServiceAccount() + serviceAddress := serviceAcc.Address + + dep := config.Dependency{ + Name: "Hello", + RemoteSource: config.RemoteSource{ + NetworkName: "emulator", + Address: serviceAddress, + ContractName: "Hello", + }, + } + + state.Dependencies().AddOrUpdate(dep) + + t.Run("Success", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(0).(flow.Address) + assert.Equal(t, addr.String(), serviceAcc.Address.String()) + racc := tests.NewAccountWithAddress(addr.String()) + racc.Contracts = map[string][]byte{ + tests.ContractHelloString.Name: tests.ContractHelloString.Source, + } + + gw.GetAccount.Return(racc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + } + + err := di.install() + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} diff --git a/internal/dependencymanager/fileutils.go b/internal/dependencymanager/fileutils.go deleted file mode 100644 index 485dc57ba..000000000 --- a/internal/dependencymanager/fileutils.go +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dependencymanager - -import ( - "os" - "path/filepath" -) - -func contractFileExists(address, contractName string) bool { - path := filepath.Join("imports", address, contractName) - _, err := os.Stat(path) - return !os.IsNotExist(err) -} - -func createContractFile(address, contractName, data string) error { - path := filepath.Join("imports", address, contractName) - - dir := filepath.Dir(path) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return err - } - - return os.WriteFile(path, []byte(data), 0644) -} diff --git a/internal/dependencymanager/install_test.go b/internal/dependencymanager/install_test.go deleted file mode 100644 index 8306b2610..000000000 --- a/internal/dependencymanager/install_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package dependencymanager - -import ( - "github.com/onflow/flow-cli/flowkit/config" - "github.com/onflow/flow-cli/flowkit/output" - "github.com/onflow/flow-cli/flowkit/tests" - "github.com/onflow/flow-cli/internal/command" - "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-go-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "testing" -) - -func TestInstallDependencies(t *testing.T) { - logger := output.NewStdoutLogger(output.NoneLog) - srv, state, _ := util.TestMocks(t) - - dep := config.Dependency{ - Name: "Hello", - RemoteSource: config.RemoteSource{ - NetworkName: "emulator", - Address: flow.HexToAddress("0000000000000001"), - ContractName: "Hello", - }, - } - - state.Dependencies().AddOrUpdate(dep) - - t.Run("Success", func(t *testing.T) { - inArgs := []string{"0x1"} - - srv.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(1).(flow.Address) - assert.Equal(t, "0000000000000001", addr.String()) - srv.GetAccount.Return(tests.NewAccountWithContracts(inArgs[0], tests.ContractHelloString), nil) - }) - - _, err := install([]string{}, command.GlobalFlags{}, logger, srv.Mock, state) - assert.NoError(t, err, "Failed to install dependencies") - - fileContent, err := state.ReaderWriter().ReadFile("imports/0000000000000001/Hello") - assert.NoError(t, err, "Failed to read generated file") - assert.NotNil(t, fileContent) - }) -} From ab6b1c6c006b26663d674c9e3b98d3d37830eb98 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:47:39 -0800 Subject: [PATCH 68/95] Change ci to di --- .../dependencymanager/dependencyinstaller.go | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 79287ea9c..171797f3c 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -76,17 +76,17 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } -func (ci *DependencyInstaller) install() error { - for _, dependency := range *ci.State.Dependencies() { - if err := ci.processDependency(dependency); err != nil { - ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) +func (di *DependencyInstaller) install() error { + for _, dependency := range *di.State.Dependencies() { + if err := di.processDependency(dependency); err != nil { + di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) return err } } return nil } -func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { +func (di *DependencyInstaller) add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) @@ -107,20 +107,20 @@ func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { }, } - if err := ci.processDependency(dep); err != nil { + if err := di.processDependency(dep); err != nil { return fmt.Errorf("error processing dependency: %w", err) } return nil } -func (ci *DependencyInstaller) processDependency(dependency config.Dependency) error { +func (di *DependencyInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) + return di.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) } -func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - account, err := ci.Gateways[networkName].GetAccount(address) +func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { + account, err := di.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %w", err) } @@ -149,7 +149,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo if parsedContractName == contractName { - if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { + if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -159,7 +159,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { defer wg.Done() - err := ci.fetchDependencies(networkName, importAddress, contractName, contractName) + err := di.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err } @@ -181,32 +181,32 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } -func (ci *DependencyInstaller) contractFileExists(address, contractName string) bool { +func (di *DependencyInstaller) contractFileExists(address, contractName string) bool { path := filepath.Join("imports", address, contractName) - _, err := ci.State.ReaderWriter().Stat(path) + _, err := di.State.ReaderWriter().Stat(path) return err == nil } -func (ci *DependencyInstaller) createContractFile(address, contractName, data string) error { +func (di *DependencyInstaller) createContractFile(address, contractName, data string) error { path := filepath.Join("imports", address, contractName) dir := filepath.Dir(path) - if err := ci.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { + if err := di.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { return fmt.Errorf("error creating directories: %w", err) } - if err := ci.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { + if err := di.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { return fmt.Errorf("error writing file: %w", err) } return nil } -func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { - ci.Mutex.Lock() - defer ci.Mutex.Unlock() +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { + di.Mutex.Lock() + defer di.Mutex.Unlock() hash := sha256.New() hash.Write(program.DevelopmentCode()) @@ -215,11 +215,11 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) - dependency := ci.State.Dependencies().ByName(assignedName) + dependency := di.State.Dependencies().ByName(assignedName) // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { - ci.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) + di.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) os.Exit(0) return nil } @@ -234,24 +234,24 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !ci.contractFileExists(contractAddr, contractName) { - if err := ci.createContractFile(contractAddr, contractName, contractData); err != nil { + if !di.contractFileExists(contractAddr, contractName) { + if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } - ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) } - err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) + err := di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { - ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) + di.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err } return nil } -func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { +func (di *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ @@ -262,17 +262,17 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Version: contractHash, } - isNewDep := ci.State.Dependencies().ByName(dep.Name) == nil + isNewDep := di.State.Dependencies().ByName(dep.Name) == nil - ci.State.Dependencies().AddOrUpdate(dep) - ci.State.Contracts().AddDependencyAsContract(dep, networkName) - err := ci.State.SaveDefault() + di.State.Dependencies().AddOrUpdate(dep) + di.State.Contracts().AddDependencyAsContract(dep, networkName) + err := di.State.SaveDefault() if err != nil { return err } if isNewDep { - ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) } return nil From 85369210b1af50c56b139f4b35bdc626c0e40c9c Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:50:39 -0800 Subject: [PATCH 69/95] Run lintfix --- flowkit/tests/resources.go | 1 + internal/dependencymanager/dependencyinstaller_test.go | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/flowkit/tests/resources.go b/flowkit/tests/resources.go index e889a002e..49808b6c2 100644 --- a/flowkit/tests/resources.go +++ b/flowkit/tests/resources.go @@ -20,6 +20,7 @@ package tests import ( "fmt" + "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go-sdk" diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index f4ff585d1..0db7d641b 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -2,16 +2,18 @@ package dependencymanager import ( "fmt" + "testing" + + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/onflow/flow-cli/flowkit/config" "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/gateway/mocks" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/flowkit/tests" "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-go-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "testing" ) func TestDependencyInstallerInstall(t *testing.T) { From d578518f121504f2c1c8182b08ae25da4a5cec0d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:54:24 -0800 Subject: [PATCH 70/95] Add license header --- .../dependencyinstaller_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 0db7d641b..2536eef7e 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( From b28de617d85edcdf339d87bec32b4735020eae91 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:16:40 -0800 Subject: [PATCH 71/95] Make add and install public --- internal/dependencymanager/add.go | 2 +- internal/dependencymanager/dependencyinstaller.go | 4 ++-- internal/dependencymanager/dependencyinstaller_test.go | 2 +- internal/dependencymanager/install.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 7cb4399d4..614caeb64 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -56,7 +56,7 @@ func add( dep := args[0] installer := NewDependencyInstaller(logger, state) - if err := installer.add(dep, addFlags.name); err != nil { + if err := installer.Add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 171797f3c..a122bd21b 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -76,7 +76,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } -func (di *DependencyInstaller) install() error { +func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -86,7 +86,7 @@ func (di *DependencyInstaller) install() error { return nil } -func (di *DependencyInstaller) add(depRemoteSource, customName string) error { +func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 2536eef7e..7bede1392 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -77,7 +77,7 @@ func TestDependencyInstallerInstall(t *testing.T) { State: state, } - err := di.install() + err := di.Install() assert.NoError(t, err, "Failed to install dependencies") filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 751a8a087..049a348b2 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -51,7 +51,7 @@ func install( logger.Info("🔄 Installing dependencies from flow.json...") installer := NewDependencyInstaller(logger, state) - if err := installer.install(); err != nil { + if err := installer.Install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } From 645a63844924a2087c81568773404d4d6774b1c6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:24:05 -0800 Subject: [PATCH 72/95] Fix typo --- internal/dependencymanager/dependencyinstaller_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 7bede1392..7a0ce0d3b 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -59,12 +59,12 @@ func TestDependencyInstallerInstall(t *testing.T) { gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(0).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) - racc := tests.NewAccountWithAddress(addr.String()) - racc.Contracts = map[string][]byte{ + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ tests.ContractHelloString.Name: tests.ContractHelloString.Source, } - gw.GetAccount.Return(racc, nil) + gw.GetAccount.Return(acc, nil) }) di := &DependencyInstaller{ From cbef20c75ab1f74d7c61eabefa767f41965d9bb3 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:29:08 -0800 Subject: [PATCH 73/95] Add test for DependencyInstaller.Add --- .../dependencyinstaller_test.go | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 7a0ce0d3b..8f5d92f17 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -80,7 +80,50 @@ func TestDependencyInstallerInstall(t *testing.T) { err := di.Install() assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) + filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} + +func TestDependencyInstallerAdd(t *testing.T) { + + logger := output.NewStdoutLogger(output.NoneLog) + _, state, _ := util.TestMocks(t) + + serviceAcc, _ := state.EmulatorServiceAccount() + serviceAddress := serviceAcc.Address + + t.Run("Success", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(0).(flow.Address) + assert.Equal(t, addr.String(), serviceAcc.Address.String()) + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ + tests.ContractHelloString.Name: tests.ContractHelloString.Source, + } + + gw.GetAccount.Return(acc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + } + + remoteSourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) + err := di.Add(remoteSourceStr, "") + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) From 9066dcdbad36ffdd5159ac8ce06cdb4e91051543 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:41:02 -0800 Subject: [PATCH 74/95] Create max number of concurrent routines --- internal/dependencymanager/dependencyinstaller.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index a122bd21b..1ed41f4db 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -135,8 +135,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo var wg sync.WaitGroup errCh := make(chan error, len(account.Contracts)) - for _, contract := range account.Contracts { + // Create a max number of goroutines so that we don't rate limit the access node + maxGoroutines := 5 + semaphore := make(chan struct{}, maxGoroutines) + for _, contract := range account.Contracts { program, err := project.NewProgram(contract, nil, "") if err != nil { return fmt.Errorf("failed to parse program: %w", err) @@ -148,7 +151,6 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { - if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -158,7 +160,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo for _, imp := range imports { wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { - defer wg.Done() + semaphore <- struct{}{} + defer func() { + <-semaphore + wg.Done() + }() err := di.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err @@ -171,6 +177,7 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Wait() close(errCh) + close(semaphore) for err := range errCh { if err != nil { From 4dce879d0fd2e42ab77e97594b62669051a0eb04 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:01:35 -0800 Subject: [PATCH 75/95] Move mutex to only file system --- .../dependencymanager/dependencyinstaller.go | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 1ed41f4db..856d37503 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -211,10 +211,22 @@ func (di *DependencyInstaller) createContractFile(address, contractName, data st return nil } -func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { +func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, contractData, networkName string) error { di.Mutex.Lock() defer di.Mutex.Unlock() + if !di.contractFileExists(contractAddr, contractName) { + if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { + return fmt.Errorf("failed to create contract file: %w", err) + } + + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + } + + return nil +} + +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.DevelopmentCode()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) @@ -241,15 +253,12 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !di.contractFileExists(contractAddr, contractName) { - if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { - return fmt.Errorf("failed to create contract file: %w", err) - } - - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + err := di.handleFileSystem(contractAddr, contractName, contractData, networkName) + if err != nil { + return fmt.Errorf("error handling file system: %w", err) } - err := di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) + err = di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err From bde4dfc4f411d42e0d8889c65025312fa7851cb9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:20:40 -0800 Subject: [PATCH 76/95] Add comments to exposed methods --- internal/dependencymanager/dependencyinstaller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 856d37503..b4b066574 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -47,6 +47,7 @@ type DependencyInstaller struct { Mutex sync.Mutex } +// NewDependencyInstaller creates a new instance of DependencyInstaller func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { @@ -76,6 +77,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } +// Install processes all the dependencies in the state and installs them and any dependencies they have func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { @@ -86,6 +88,7 @@ func (di *DependencyInstaller) Install() error { return nil } +// Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { From fb59c4c0af1e81b06d9ef39c5c633f03ba689fcc Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:31:11 -0800 Subject: [PATCH 77/95] Make variables private and cleanup --- flowkit/config/contract.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 300cd013e..7ec064529 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -113,15 +113,23 @@ func (c *Contracts) Remove(name string) error { } const ( - NetworkEmulator = "emulator" - NetworkTestnet = "testnet" - NetworkMainnet = "mainnet" + networkEmulator = "emulator" + networkTestnet = "testnet" + networkMainnet = "mainnet" ) +func supportedNetworks() []string { + return []string{ + networkEmulator, + networkTestnet, + networkMainnet, + } +} + var networkToChainID = map[string]flowGo.ChainID{ - NetworkEmulator: flowGo.Emulator, - NetworkTestnet: flowGo.Testnet, - NetworkMainnet: flowGo.Mainnet, + networkEmulator: flowGo.Emulator, + networkTestnet: flowGo.Testnet, + networkMainnet: flowGo.Mainnet, } func isCoreContract(networkName, contractName, contractAddress string) bool { @@ -154,7 +162,7 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s // If core contract found by name and address matches, then use all core contract aliases across networks if isCoreContract(networkName, dependency.RemoteSource.ContractName, dependency.RemoteSource.Address.String()) { - for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { + for _, networkStr := range supportedNetworks() { coreContract := getCoreContractByName(networkStr, dependency.RemoteSource.ContractName) if coreContract != nil { aliases = append(aliases, Alias{ From 55e55a0d9a60911762e619055dd306933fa8e632 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:12:08 -0800 Subject: [PATCH 78/95] Move command --- cmd/flow/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/flow/main.go b/cmd/flow/main.go index dc8c0dca5..820097b4c 100644 --- a/cmd/flow/main.go +++ b/cmd/flow/main.go @@ -122,10 +122,6 @@ func main() { cmd.AddCommand(dependencymanager.Cmd) command.InitFlags(cmd) - cmd.AddGroup(&cobra.Group{ - ID: "manager", - Title: "🔗 Contract Manager", - }) cmd.AddGroup(&cobra.Group{ ID: "super", Title: "🔥 Super Commands", @@ -150,6 +146,10 @@ func main() { ID: "security", Title: "🔒 Flow Security", }) + cmd.AddGroup(&cobra.Group{ + ID: "manager", + Title: "🔗 Contract Manager", + }) cmd.SetUsageTemplate(command.UsageTemplate) From 5a7b75d1cc029681d377c5e3acb02a15c6d9f0d4 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:14:53 -0800 Subject: [PATCH 79/95] Add examples --- internal/dependencymanager/add.go | 7 ++++--- internal/dependencymanager/install.go | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 614caeb64..ba5446119 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -36,9 +36,10 @@ var addFlags = addFlagsCollection{} var addCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "add", - Short: "Add a single contract and its dependencies.", - Args: cobra.ExactArgs(1), + Use: "add ", + Short: "Add a single contract and its dependencies.", + Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", + Args: cobra.ExactArgs(1), }, Flags: &addFlags, RunS: add, diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 049a348b2..13e8ce29e 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -34,8 +34,9 @@ var installFlags = installFlagsCollection{} var installCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "install", - Short: "Install contract and dependencies.", + Use: "install", + Short: "Install contract and dependencies.", + Example: "flow dependencies install", }, Flags: &installFlags, RunS: install, From e4b5efbae925f445b7bd0792fc9235dcf25ecdea Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:34:08 -0800 Subject: [PATCH 80/95] Add .cdc file extension --- internal/dependencymanager/dependencyinstaller.go | 6 ++++-- internal/dependencymanager/dependencyinstaller_test.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index b4b066574..05cb4fb95 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -192,7 +192,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } func (di *DependencyInstaller) contractFileExists(address, contractName string) bool { - path := filepath.Join("imports", address, contractName) + fileName := fmt.Sprintf("%s.cdc", contractName) + path := filepath.Join("imports", address, fileName) _, err := di.State.ReaderWriter().Stat(path) @@ -200,7 +201,8 @@ func (di *DependencyInstaller) contractFileExists(address, contractName string) } func (di *DependencyInstaller) createContractFile(address, contractName, data string) error { - path := filepath.Join("imports", address, contractName) + fileName := fmt.Sprintf("%s.cdc", contractName) + path := filepath.Join("imports", address, fileName) dir := filepath.Dir(path) if err := di.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 8f5d92f17..5e44609f3 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -80,7 +80,7 @@ func TestDependencyInstallerInstall(t *testing.T) { err := di.Install() assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) @@ -123,7 +123,7 @@ func TestDependencyInstallerAdd(t *testing.T) { err := di.Add(remoteSourceStr, "") assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) From 843255dcd8bc2c7c01459914111d390533c5253e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:36:29 -0800 Subject: [PATCH 81/95] Add context to error --- flowkit/config/dependency.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 2a7f82c8e..4e543f657 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -28,13 +28,13 @@ import ( func ParseRemoteSourceString(s string) (network, address, contractName string, err error) { parts := strings.Split(s, "://") if len(parts) != 2 { - return "", "", "", fmt.Errorf("invalid dependency source format") + return "", "", "", fmt.Errorf("invalid dependency source format: %s", s) } network = parts[0] subParts := strings.Split(parts[1], ".") if len(subParts) != 2 { - return "", "", "", fmt.Errorf("invalid dependency source format") + return "", "", "", fmt.Errorf("invalid dependency source format: %s", s) } address = subParts[0] contractName = subParts[1] From c14954b5b0a252da1a110a865725eccd0c378054 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:46:08 -0800 Subject: [PATCH 82/95] Rename variable --- flowkit/project/program.go | 26 +++++++++---------- flowkit/project/program_test.go | 2 +- .../dependencymanager/dependencyinstaller.go | 4 +-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/flowkit/project/program.go b/flowkit/project/program.go index 8689187d1..8a8f0129b 100644 --- a/flowkit/project/program.go +++ b/flowkit/project/program.go @@ -29,11 +29,11 @@ import ( ) type Program struct { - code []byte - args []cadence.Value - location string - astProgram *ast.Program - developmentCode []byte + code []byte + args []cadence.Value + location string + astProgram *ast.Program + codeWithUnprocessedImports []byte } func NewProgram(code []byte, args []cadence.Value, location string) (*Program, error) { @@ -43,11 +43,11 @@ func NewProgram(code []byte, args []cadence.Value, location string) (*Program, e } return &Program{ - code: code, - args: args, - location: location, - astProgram: astProgram, - developmentCode: code, // has converted import syntax e.g. 'import "Foo"' + code: code, + args: args, + location: location, + astProgram: astProgram, + codeWithUnprocessedImports: code, // has converted import syntax e.g. 'import "Foo"' }, nil } @@ -111,8 +111,8 @@ func (p *Program) Code() []byte { return p.code } -func (p *Program) DevelopmentCode() []byte { - return p.developmentCode +func (p *Program) CodeWithUnprocessedImports() []byte { + return p.codeWithUnprocessedImports } func (p *Program) Name() (string, error) { @@ -141,7 +141,7 @@ func (p *Program) ConvertImports() { addressImportRegex := regexp.MustCompile(`import\s+(\w+)\s+from\s+0x[0-9a-fA-F]+`) modifiedCode := addressImportRegex.ReplaceAllString(code, `import "$1"`) - p.developmentCode = []byte(modifiedCode) + p.codeWithUnprocessedImports = []byte(modifiedCode) } func (p *Program) reload() { diff --git a/flowkit/project/program_test.go b/flowkit/project/program_test.go index 24afdd0c6..4eeaf4c60 100644 --- a/flowkit/project/program_test.go +++ b/flowkit/project/program_test.go @@ -210,7 +210,7 @@ func TestProgram(t *testing.T) { program.ConvertImports() - assert.Equal(t, string(expected), string(program.DevelopmentCode())) + assert.Equal(t, string(expected), string(program.CodeWithUnprocessedImports())) }) } diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 05cb4fb95..f37c555ac 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -233,11 +233,11 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() - hash.Write(program.DevelopmentCode()) + hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) program.ConvertImports() - contractData := string(program.DevelopmentCode()) + contractData := string(program.CodeWithUnprocessedImports()) dependency := di.State.Dependencies().ByName(assignedName) From fb2101ec28ee39c9ea16dffc14d26fc912f9fdfb Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:36:16 -0800 Subject: [PATCH 83/95] Error if NewDependencyInstaller errors --- internal/dependencymanager/add.go | 7 ++++++- internal/dependencymanager/dependencyinstaller.go | 10 +++++----- internal/dependencymanager/install.go | 7 ++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index ba5446119..2cf9cd1e5 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -56,7 +56,12 @@ func add( dep := args[0] - installer := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state) + if err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + if err := installer.Add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index f37c555ac..987cd986c 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -48,20 +48,20 @@ type DependencyInstaller struct { } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) + return nil, fmt.Errorf("error creating emulator gateway: %v", err) } testnetGateway, err := gateway.NewGrpcGateway(config.TestnetNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating testnet gateway: %v", err)) + return nil, fmt.Errorf("error creating testnet gateway: %v", err) } mainnetGateway, err := gateway.NewGrpcGateway(config.MainnetNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating mainnet gateway: %v", err)) + return nil, fmt.Errorf("error creating mainnet gateway: %v", err) } gateways := map[string]gateway.Gateway{ @@ -74,7 +74,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende Gateways: gateways, Logger: logger, State: state, - } + }, nil } // Install processes all the dependencies in the state and installs them and any dependencies they have diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 13e8ce29e..2e3e8fb01 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -51,7 +51,12 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state) + if err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + if err := installer.Install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 6b695e106646820a93694465377aacc3045c1ee1 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:38:26 -0800 Subject: [PATCH 84/95] Change to constant --- flowkit/config/contract.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 7ec064529..0d3ffcd33 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -112,6 +112,8 @@ func (c *Contracts) Remove(name string) error { return nil } +const dependencyManagerDirectory = "imports" + const ( networkEmulator = "emulator" networkTestnet = "testnet" @@ -185,7 +187,7 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s contract := Contract{ Name: dependency.Name, - Location: filepath.ToSlash(fmt.Sprintf("imports/%s/%s", dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), + Location: filepath.ToSlash(fmt.Sprintf("%s/%s/%s", dependencyManagerDirectory, dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), Aliases: aliases, IsDependency: true, } From 18278f96291d06dbe3cdbb98ab2645d86a09acf6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:46:22 -0800 Subject: [PATCH 85/95] Error if not found --- internal/dependencymanager/add.go | 2 +- internal/dependencymanager/dependencyinstaller.go | 9 +++++++++ internal/dependencymanager/install.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 2cf9cd1e5..fb4d58c17 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -67,7 +67,7 @@ func add( return nil, err } - logger.Info("✅ Dependencies installed. Check your flow.json") + logger.Info("✅ Dependencies installation complete. Check your flow.json") return nil, nil } diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 987cd986c..d190c9fee 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -142,6 +142,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo maxGoroutines := 5 semaphore := make(chan struct{}, maxGoroutines) + found := false + for _, contract := range account.Contracts { program, err := project.NewProgram(contract, nil, "") if err != nil { @@ -154,6 +156,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { + found = true + if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -176,6 +180,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } } } + + if !found { + errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) + di.Logger.Error(errMsg) + } } wg.Wait() diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index 2e3e8fb01..f21ec0194 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -62,7 +62,7 @@ func install( return nil, err } - logger.Info("✅ Dependencies installed. Check your flow.json") + logger.Info("✅ Dependencies installation complete. Check your flow.json") return nil, nil } From 6f80b222ac4e024d76394e9d1078f723ac873f93 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:13:56 -0800 Subject: [PATCH 86/95] Fix found check --- internal/dependencymanager/dependencyinstaller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index d190c9fee..dbb1133c4 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -180,11 +180,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } } } + } - if !found { - errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) - di.Logger.Error(errMsg) - } + if !found { + errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) + di.Logger.Error(errMsg) } wg.Wait() From 41916c875ac0da3abf7841cf750f549f0db866d9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:18:31 -0800 Subject: [PATCH 87/95] Fix .cdc extension --- flowkit/config/contract.go | 2 +- flowkit/config/contract_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index 0d3ffcd33..eaca63395 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -187,7 +187,7 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s contract := Contract{ Name: dependency.Name, - Location: filepath.ToSlash(fmt.Sprintf("%s/%s/%s", dependencyManagerDirectory, dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), + Location: filepath.ToSlash(fmt.Sprintf("%s/%s/%s.cdc", dependencyManagerDirectory, dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), Aliases: aliases, IsDependency: true, } diff --git a/flowkit/config/contract_test.go b/flowkit/config/contract_test.go index 9854768c9..1f68bff81 100644 --- a/flowkit/config/contract_test.go +++ b/flowkit/config/contract_test.go @@ -106,6 +106,6 @@ func TestContracts_AddDependencyAsContract(t *testing.T) { contract, err := contracts.ByName("testcontract") assert.NoError(t, err) - assert.Equal(t, "imports/0000000000abcdef/TestContract", contract.Location) + assert.Equal(t, "imports/0000000000abcdef/TestContract.cdc", contract.Location) assert.Len(t, contract.Aliases, 1) } From e9d10e351036e0e010fa3482859be0e727ca77cb Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:55:56 -0800 Subject: [PATCH 88/95] Change name --- cmd/flow/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/flow/main.go b/cmd/flow/main.go index 820097b4c..79fd78961 100644 --- a/cmd/flow/main.go +++ b/cmd/flow/main.go @@ -148,7 +148,7 @@ func main() { }) cmd.AddGroup(&cobra.Group{ ID: "manager", - Title: "🔗 Contract Manager", + Title: "🔗 Dependency Manager", }) cmd.SetUsageTemplate(command.UsageTemplate) From 75054c645df22da8fc1b329162541b17ad2733cb Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:51:21 -0800 Subject: [PATCH 89/95] Change remoteSource to source --- flowkit/config/contract.go | 12 +++--- flowkit/config/contract_test.go | 2 +- flowkit/config/dependency.go | 12 +++--- flowkit/config/json/config.go | 2 +- flowkit/config/json/dependency.go | 38 +++++++++---------- flowkit/config/json/dependency_test.go | 2 +- flowkit/schema.json | 4 +- .../dependencymanager/dependencyinstaller.go | 16 ++++---- .../dependencyinstaller_test.go | 6 +-- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/flowkit/config/contract.go b/flowkit/config/contract.go index eaca63395..bcfa883d7 100644 --- a/flowkit/config/contract.go +++ b/flowkit/config/contract.go @@ -163,9 +163,9 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s var aliases []Alias // If core contract found by name and address matches, then use all core contract aliases across networks - if isCoreContract(networkName, dependency.RemoteSource.ContractName, dependency.RemoteSource.Address.String()) { + if isCoreContract(networkName, dependency.Source.ContractName, dependency.Source.Address.String()) { for _, networkStr := range supportedNetworks() { - coreContract := getCoreContractByName(networkStr, dependency.RemoteSource.ContractName) + coreContract := getCoreContractByName(networkStr, dependency.Source.ContractName) if coreContract != nil { aliases = append(aliases, Alias{ Network: networkStr, @@ -177,17 +177,17 @@ func (c *Contracts) AddDependencyAsContract(dependency Dependency, networkName s aliases = append(aliases, dependency.Aliases...) } - // If no core contract match, then use the address in remoteSource as alias + // If no core contract match, then use the address in source as alias if len(aliases) == 0 { aliases = append(aliases, Alias{ - Network: dependency.RemoteSource.NetworkName, - Address: dependency.RemoteSource.Address, + Network: dependency.Source.NetworkName, + Address: dependency.Source.Address, }) } contract := Contract{ Name: dependency.Name, - Location: filepath.ToSlash(fmt.Sprintf("%s/%s/%s.cdc", dependencyManagerDirectory, dependency.RemoteSource.Address, dependency.RemoteSource.ContractName)), + Location: filepath.ToSlash(fmt.Sprintf("%s/%s/%s.cdc", dependencyManagerDirectory, dependency.Source.Address, dependency.Source.ContractName)), Aliases: aliases, IsDependency: true, } diff --git a/flowkit/config/contract_test.go b/flowkit/config/contract_test.go index 1f68bff81..2b9ab21f0 100644 --- a/flowkit/config/contract_test.go +++ b/flowkit/config/contract_test.go @@ -95,7 +95,7 @@ func TestContracts_AddDependencyAsContract(t *testing.T) { contracts := Contracts{} contracts.AddDependencyAsContract(Dependency{ Name: "testcontract", - RemoteSource: RemoteSource{ + Source: Source{ NetworkName: "testnet", Address: flow.HexToAddress("0x0000000000abcdef"), ContractName: "TestContract", diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index 4e543f657..e9215d4b6 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -25,7 +25,7 @@ import ( "github.com/onflow/flow-go-sdk" ) -func ParseRemoteSourceString(s string) (network, address, contractName string, err error) { +func ParseSourceString(s string) (network, address, contractName string, err error) { parts := strings.Split(s, "://") if len(parts) != 2 { return "", "", "", fmt.Errorf("invalid dependency source format: %s", s) @@ -42,17 +42,17 @@ func ParseRemoteSourceString(s string) (network, address, contractName string, e return network, address, contractName, nil } -type RemoteSource struct { +type Source struct { NetworkName string Address flow.Address ContractName string } type Dependency struct { - Name string - RemoteSource RemoteSource - Version string - Aliases Aliases + Name string + Source Source + Version string + Aliases Aliases } type Dependencies []Dependency diff --git a/flowkit/config/json/config.go b/flowkit/config/json/config.go index bc1079772..af2f96c8e 100644 --- a/flowkit/config/json/config.go +++ b/flowkit/config/json/config.go @@ -77,7 +77,7 @@ func (j *jsonConfig) transformToConfig() (*config.Config, error) { // Add dependencies as contracts so they can be used in the project just like any other contract. for _, dep := range dependencies { - conf.Contracts.AddDependencyAsContract(dep, dep.RemoteSource.NetworkName) + conf.Contracts.AddDependencyAsContract(dep, dep.Source.NetworkName) } return conf, nil diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index 46cc27822..a31216900 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -39,29 +39,29 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { var dep config.Dependency if dependency.Simple != "" { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependency.Simple) + depNetwork, depAddress, depContractName, err := config.ParseSourceString(dependency.Simple) if err != nil { - return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) + return nil, fmt.Errorf("error parsing source for dependency %s: %w", dependencyName, err) } dep = config.Dependency{ Name: dependencyName, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: depNetwork, Address: flow.HexToAddress(depAddress), ContractName: depContractName, }, } } else { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(dependency.Extended.RemoteSource) + depNetwork, depAddress, depContractName, err := config.ParseSourceString(dependency.Extended.Source) if err != nil { - return nil, fmt.Errorf("error parsing remote source for dependency %s: %w", dependencyName, err) + return nil, fmt.Errorf("error parsing source for dependency %s: %w", dependencyName, err) } dep = config.Dependency{ Name: dependencyName, Version: dependency.Extended.Version, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: depNetwork, Address: flow.HexToAddress(depAddress), ContractName: depContractName, @@ -99,9 +99,9 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC jsonDeps[dep.Name] = jsonDependency{ Extended: jsonDependencyExtended{ - RemoteSource: buildRemoteSourceString(dep.RemoteSource), - Version: dep.Version, - Aliases: aliases, + Source: buildSourceString(dep.Source), + Version: dep.Version, + Aliases: aliases, }, } } @@ -109,23 +109,23 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC return jsonDeps } -func buildRemoteSourceString(remoteSource config.RemoteSource) string { +func buildSourceString(source config.Source) string { var builder strings.Builder - builder.WriteString(remoteSource.NetworkName) + builder.WriteString(source.NetworkName) builder.WriteString("://") - builder.WriteString(remoteSource.Address.String()) + builder.WriteString(source.Address.String()) builder.WriteString(".") - builder.WriteString(remoteSource.ContractName) + builder.WriteString(source.ContractName) return builder.String() } // jsonDependencyExtended for json parsing advanced config. type jsonDependencyExtended struct { - RemoteSource string `json:"remoteSource"` - Version string `json:"version"` - Aliases map[string]string `json:"aliases"` + Source string `json:"source"` + Version string `json:"version"` + Aliases map[string]string `json:"aliases"` } // jsonDependency structure for json parsing. @@ -135,13 +135,13 @@ type jsonDependency struct { } func (j *jsonDependency) UnmarshalJSON(b []byte) error { - var remoteSource string + var source string var extendedFormat jsonDependencyExtended // simple - err := json.Unmarshal(b, &remoteSource) + err := json.Unmarshal(b, &source) if err == nil { - j.Simple = remoteSource + j.Simple = source return nil } diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index a1ce35130..4d2d76d58 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -52,7 +52,7 @@ func Test_TransformDependenciesToJSON(t *testing.T) { bOut := []byte(`{ "HelloWorld": { - "remoteSource": "testnet://877931736ee77cff.HelloWorld", + "source": "testnet://877931736ee77cff.HelloWorld", "version": "", "aliases": {} } diff --git a/flowkit/schema.json b/flowkit/schema.json index eae3feeed..2e5f13145 100644 --- a/flowkit/schema.json +++ b/flowkit/schema.json @@ -234,7 +234,7 @@ }, "jsonDependencyExtended": { "properties": { - "remoteSource": { + "source": { "type": "string" }, "version": { @@ -252,7 +252,7 @@ "additionalProperties": false, "type": "object", "required": [ - "remoteSource", + "source", "version", "aliases" ] diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index dbb1133c4..7ca177a40 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -89,10 +89,10 @@ func (di *DependencyInstaller) Install() error { } // Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state -func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) +func (di *DependencyInstaller) Add(depSource, customName string) error { + depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource) if err != nil { - return fmt.Errorf("error parsing remote source: %w", err) + return fmt.Errorf("error parsing source: %w", err) } name := depContractName @@ -103,7 +103,7 @@ func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { dep := config.Dependency{ Name: name, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: depNetwork, Address: flowsdk.HexToAddress(depAddress), ContractName: depContractName, @@ -118,8 +118,8 @@ func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { } func (di *DependencyInstaller) processDependency(dependency config.Dependency) error { - depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return di.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) + depAddress := flowsdk.HexToAddress(dependency.Source.Address.String()) + return di.fetchDependencies(dependency.Source.NetworkName, depAddress, dependency.Name, dependency.Source.ContractName) } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { @@ -251,7 +251,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as dependency := di.State.Dependencies().ByName(assignedName) // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue - if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { + if dependency != nil && (dependency.Source.NetworkName != networkName || dependency.Source.Address.String() != contractAddr) { di.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) os.Exit(0) return nil @@ -284,7 +284,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as func (di *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: networkName, Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 5e44609f3..9a7e1ac59 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -44,7 +44,7 @@ func TestDependencyInstallerInstall(t *testing.T) { dep := config.Dependency{ Name: "Hello", - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: "emulator", Address: serviceAddress, ContractName: "Hello", @@ -119,8 +119,8 @@ func TestDependencyInstallerAdd(t *testing.T) { State: state, } - remoteSourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) - err := di.Add(remoteSourceStr, "") + sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) + err := di.Add(sourceStr, "") assert.NoError(t, err, "Failed to install dependencies") filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) From 50282449a0d6716960532681196c732b4d146de9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:55:14 -0800 Subject: [PATCH 90/95] Change version to hash --- flowkit/config/dependency.go | 2 +- flowkit/config/json/dependency.go | 8 ++++---- flowkit/config/json/dependency_test.go | 2 +- internal/dependencymanager/dependencyinstaller.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/flowkit/config/dependency.go b/flowkit/config/dependency.go index e9215d4b6..68c862a19 100644 --- a/flowkit/config/dependency.go +++ b/flowkit/config/dependency.go @@ -51,7 +51,7 @@ type Source struct { type Dependency struct { Name string Source Source - Version string + Hash string Aliases Aliases } diff --git a/flowkit/config/json/dependency.go b/flowkit/config/json/dependency.go index a31216900..d724ff6a5 100644 --- a/flowkit/config/json/dependency.go +++ b/flowkit/config/json/dependency.go @@ -59,8 +59,8 @@ func (j jsonDependencies) transformToConfig() (config.Dependencies, error) { } dep = config.Dependency{ - Name: dependencyName, - Version: dependency.Extended.Version, + Name: dependencyName, + Hash: dependency.Extended.Hash, Source: config.Source{ NetworkName: depNetwork, Address: flow.HexToAddress(depAddress), @@ -100,7 +100,7 @@ func transformDependenciesToJSON(configDependencies config.Dependencies, configC jsonDeps[dep.Name] = jsonDependency{ Extended: jsonDependencyExtended{ Source: buildSourceString(dep.Source), - Version: dep.Version, + Hash: dep.Hash, Aliases: aliases, }, } @@ -124,7 +124,7 @@ func buildSourceString(source config.Source) string { // jsonDependencyExtended for json parsing advanced config. type jsonDependencyExtended struct { Source string `json:"source"` - Version string `json:"version"` + Hash string `json:"hash"` Aliases map[string]string `json:"aliases"` } diff --git a/flowkit/config/json/dependency_test.go b/flowkit/config/json/dependency_test.go index 4d2d76d58..3467b130c 100644 --- a/flowkit/config/json/dependency_test.go +++ b/flowkit/config/json/dependency_test.go @@ -53,7 +53,7 @@ func Test_TransformDependenciesToJSON(t *testing.T) { bOut := []byte(`{ "HelloWorld": { "source": "testnet://877931736ee77cff.HelloWorld", - "version": "", + "hash": "", "aliases": {} } }`) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index 7ca177a40..aac94f39f 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -260,7 +260,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // Check if remote source version is different from local version // If it is, ask if they want to update // If no hash, ignore - if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { + if dependency != nil && dependency.Hash != "" && dependency.Hash != originalContractDataHash { msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) if !util.GenericBoolPrompt(msg) { return nil @@ -289,7 +289,7 @@ func (di *DependencyInstaller) updateState(networkName, contractAddress, assigne Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, }, - Version: contractHash, + Hash: contractHash, } isNewDep := di.State.Dependencies().ByName(dep.Name) == nil From e11b589a383b81f19a605394192666e27b67810e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:04:18 -0800 Subject: [PATCH 91/95] Fix schema --- flowkit/schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flowkit/schema.json b/flowkit/schema.json index 2e5f13145..ad6767830 100644 --- a/flowkit/schema.json +++ b/flowkit/schema.json @@ -237,7 +237,7 @@ "source": { "type": "string" }, - "version": { + "hash": { "type": "string" }, "aliases": { @@ -253,7 +253,7 @@ "type": "object", "required": [ "source", - "version", + "hash", "aliases" ] }, From 9bff38ee5c785e60f95bdccc395c5cf5f959e96e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:11:51 -0800 Subject: [PATCH 92/95] Change import naming. Don't break flowkit --- flowkit/flowkit.go | 6 +++--- flowkit/project/deployment.go | 2 +- flowkit/project/imports.go | 2 +- flowkit/project/program.go | 10 +++++----- flowkit/project/program_test.go | 6 +++--- internal/dependencymanager/dependencyinstaller.go | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/flowkit/flowkit.go b/flowkit/flowkit.go index 8741fe1bf..b2e21ddd7 100644 --- a/flowkit/flowkit.go +++ b/flowkit/flowkit.go @@ -275,7 +275,7 @@ func (f *Flowkit) AddContract( return flow.EmptyID, false, err } - if program.HasPathImports() { + if program.HasImports() { contracts, err := state.DeploymentContractsByNetwork(f.network) if err != nil { return flow.EmptyID, false, err @@ -811,7 +811,7 @@ func (f *Flowkit) ExecuteScript(_ context.Context, script Script, query ScriptQu return nil, err } - if program.HasPathImports() { + if program.HasImports() { contracts, err := state.DeploymentContractsByNetwork(f.network) if err != nil { return nil, err @@ -921,7 +921,7 @@ func (f *Flowkit) BuildTransaction( return nil, err } - if program.HasPathImports() { + if program.HasImports() { if f.network == config.EmptyNetwork { return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") } diff --git a/flowkit/project/deployment.go b/flowkit/project/deployment.go index bd2467de4..f8b4f1431 100644 --- a/flowkit/project/deployment.go +++ b/flowkit/project/deployment.go @@ -137,7 +137,7 @@ func (d *Deployment) conflictExists() bool { // buildDependencies iterates over all contracts and checks the imports which are added as its dependencies. func (d *Deployment) buildDependencies() error { for _, contract := range d.contracts { - for _, location := range contract.program.pathImports() { + for _, location := range contract.program.imports() { // find contract by the path import importPath := absolutePath(contract.location, location) importContract, isPath := d.contractsByLocation[importPath] diff --git a/flowkit/project/imports.go b/flowkit/project/imports.go index 0257a6759..268b0e86e 100644 --- a/flowkit/project/imports.go +++ b/flowkit/project/imports.go @@ -44,7 +44,7 @@ func NewImportReplacer(contracts []*Contract, aliases LocationAliases) *ImportRe } func (i *ImportReplacer) Replace(program *Program) (*Program, error) { - imports := program.pathImports() + imports := program.imports() contractsLocations := i.getContractsLocations() for _, imp := range imports { diff --git a/flowkit/project/program.go b/flowkit/project/program.go index 8a8f0129b..66d0f793c 100644 --- a/flowkit/project/program.go +++ b/flowkit/project/program.go @@ -70,7 +70,7 @@ func (p *Program) HasAddressImports() bool { // Imports builds an array of all the import locations // It currently supports getting import locations as identifiers or as strings. Strings locations // can represent a file or an account name, whereas identifiers represent contract names. -func (p *Program) pathImports() []string { +func (p *Program) imports() []string { imports := make([]string, 0) for _, importDeclaration := range p.astProgram.ImportDeclarations() { @@ -84,8 +84,8 @@ func (p *Program) pathImports() []string { return imports } -func (p *Program) HasPathImports() bool { - return len(p.pathImports()) > 0 +func (p *Program) HasImports() bool { + return len(p.imports()) > 0 } func (p *Program) replaceImport(from string, to string) *Program { @@ -136,7 +136,7 @@ func (p *Program) Name() (string, error) { return "", fmt.Errorf("unable to determine contract name") } -func (p *Program) ConvertImports() { +func (p *Program) ConvertAddressImports() { code := string(p.code) addressImportRegex := regexp.MustCompile(`import\s+(\w+)\s+from\s+0x[0-9a-fA-F]+`) modifiedCode := addressImportRegex.ReplaceAllString(code, `import "$1"`) @@ -151,5 +151,5 @@ func (p *Program) reload() { } p.astProgram = astProgram - p.ConvertImports() + p.ConvertAddressImports() } diff --git a/flowkit/project/program_test.go b/flowkit/project/program_test.go index 4eeaf4c60..171f99328 100644 --- a/flowkit/project/program_test.go +++ b/flowkit/project/program_test.go @@ -98,8 +98,8 @@ func TestProgram(t *testing.T) { for i, test := range tests { program, err := NewProgram(test.code, nil, "") require.NoError(t, err, fmt.Sprintf("import test %d failed", i)) - assert.Equal(t, len(test.imports) > 0, program.HasPathImports(), fmt.Sprintf("import test %d failed", i)) - assert.Equal(t, test.imports, program.pathImports(), fmt.Sprintf("import test %d failed", i)) + assert.Equal(t, len(test.imports) > 0, program.HasImports(), fmt.Sprintf("import test %d failed", i)) + assert.Equal(t, test.imports, program.imports(), fmt.Sprintf("import test %d failed", i)) } }) @@ -208,7 +208,7 @@ func TestProgram(t *testing.T) { program, err := NewProgram(code, nil, "") require.NoError(t, err) - program.ConvertImports() + program.ConvertAddressImports() assert.Equal(t, string(expected), string(program.CodeWithUnprocessedImports())) }) diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index aac94f39f..0be79d74b 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -245,7 +245,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) - program.ConvertImports() + program.ConvertAddressImports() contractData := string(program.CodeWithUnprocessedImports()) dependency := di.State.Dependencies().ByName(assignedName) From dc122dcfa8431836cdee82bf1df982d55e147a1d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:14:09 -0800 Subject: [PATCH 93/95] change naming --- internal/dependencymanager/add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index fb4d58c17..b1866e467 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -36,7 +36,7 @@ var addFlags = addFlagsCollection{} var addCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "add ", + Use: "add ", Short: "Add a single contract and its dependencies.", Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), From 430c9a9c5aa778a19c4ee3156c7f95b025b5fc64 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:01:26 -0800 Subject: [PATCH 94/95] Add log for deployments --- internal/dependencymanager/add.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index b1866e467..3ff026d17 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -68,6 +68,8 @@ func add( } logger.Info("✅ Dependencies installation complete. Check your flow.json") + logger.Info("Make sure you add any dependencies you need to your 'deployments' section. You can do this with 'flow add config deployment'") + logger.Info("Note: core contracts do not need to be added to deployments. See this url for reference: https://github.com/onflow/flow-core-contracts") return nil, nil } From 0e640a65b312507019f07c215690253c4e325a4d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:12:34 -0800 Subject: [PATCH 95/95] Fix grammar --- internal/dependencymanager/add.go | 6 +++--- internal/dependencymanager/install.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index 3ff026d17..b972e99a1 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -67,9 +67,9 @@ func add( return nil, err } - logger.Info("✅ Dependencies installation complete. Check your flow.json") - logger.Info("Make sure you add any dependencies you need to your 'deployments' section. You can do this with 'flow add config deployment'") - logger.Info("Note: core contracts do not need to be added to deployments. See this url for reference: https://github.com/onflow/flow-core-contracts") + logger.Info("✅ Dependency installation complete. Check your flow.json") + logger.Info("Ensure you add any required dependencies to your 'deployments' section. This can be done using the 'flow add config deployment' command.") + logger.Info("Note: Core contracts do not need to be added to deployments. For reference, see this URL: https://github.com/onflow/flow-core-contracts") return nil, nil } diff --git a/internal/dependencymanager/install.go b/internal/dependencymanager/install.go index f21ec0194..cd16effb9 100644 --- a/internal/dependencymanager/install.go +++ b/internal/dependencymanager/install.go @@ -62,7 +62,7 @@ func install( return nil, err } - logger.Info("✅ Dependencies installation complete. Check your flow.json") + logger.Info("✅ Dependency installation complete. Check your flow.json") return nil, nil }