Skip to content

Commit

Permalink
fix issue where cadence 1.0 networks are mixed with old cadence netwo…
Browse files Browse the repository at this point in the history
…rks, only use core contracts of networks user wants
  • Loading branch information
bthaile committed Feb 21, 2024
1 parent eaab0d6 commit 7d4fc6a
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 56 deletions.
3 changes: 2 additions & 1 deletion flixkit/flix_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/onflow/flixkit-go/internal"
"github.com/onflow/flowkit/v2/config"
)

type FlixService interface {
Expand All @@ -14,7 +15,7 @@ type FlixService interface {
// GenerateBinding returns the generated binding given the language
GetTemplateAndCreateBinding(ctx context.Context, templateName string, lang string, destFile string) (string, error)
// GenerateTemplate returns the generated raw template
CreateTemplate(ctx context.Context, contractInfos ContractInfos, code string, preFill string) (string, error)
CreateTemplate(ctx context.Context, contractInfos ContractInfos, code string, preFill string, networks []config.Network) (string, error)
}

// FlowInteractionTemplateCadence is the interface returned from Replacing imports, it provides helper methods to assist in executing the resulting Cadence.
Expand Down
5 changes: 3 additions & 2 deletions internal/flix_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"strings"

"github.com/onflow/flowkit/v2/config"
"github.com/onflow/flowkit/v2/output"

v1 "github.com/onflow/flixkit-go/internal/v1"
Expand Down Expand Up @@ -189,11 +190,11 @@ func (s flixService) GetTemplateAndCreateBinding(ctx context.Context, templateNa
return gen.Create(template, relativeTemplateLocation)
}

func (s flixService) CreateTemplate(ctx context.Context, deployedContracts ContractInfos, code string, preFill string) (string, error) {
func (s flixService) CreateTemplate(ctx context.Context, deployedContracts ContractInfos, code string, preFill string, networks []config.Network) (string, error) {
template, _, _ := s.GetTemplate(ctx, preFill)
var gen *v1_1.Generator
var err2 error
gen, err2 = v1_1.NewTemplateGenerator(deployedContracts, s.config.Logger)
gen, err2 = v1_1.NewTemplateGenerator(deployedContracts, s.config.Logger, networks)
if err2 != nil {
return "", err2
}
Expand Down
137 changes: 90 additions & 47 deletions internal/v1_1/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,64 +33,59 @@ type ContractInfos map[string]NetworkAddressMap

type Generator struct {
deployedContracts []Contract
testnetClient *flowkit.Flowkit
mainnetClient *flowkit.Flowkit
clients []*flowkit.Flowkit
template *InteractionTemplate
}

func NewTemplateGenerator(contractInfos ContractInfos, logger output.Logger) (*Generator, error) {
func NewTemplateGenerator(contractInfos ContractInfos, logger output.Logger, networks []config.Network) (*Generator, error) {
loader := afero.Afero{Fs: afero.NewOsFs()}

gwt, err := gateway.NewGrpcGateway(config.TestnetNetwork)
if err != nil {
return nil, fmt.Errorf("could not create grpc gateway for testnet %w", err)
var clients []*flowkit.Flowkit
for _, network := range networks {
gw, err := gateway.NewGrpcGateway(network)
if err != nil {
return nil, fmt.Errorf("could not create grpc gateway for %s %w", network.Name, err)
}
state, err := flowkit.Init(loader, crypto.ECDSA_P256, crypto.SHA3_256)
if err != nil {
return nil, fmt.Errorf("could not initialize flowkit state %w", err)
}
client := flowkit.NewFlowkit(state, network, gw, logger)
clients = append(clients, client)
}

gwm, err := gateway.NewGrpcGateway(config.MainnetNetwork)
if err != nil {
return nil, fmt.Errorf("could not create grpc gateway for mainnet %w", err)
networkNames := make([]string, 0)
for _, network := range networks {
networkNames = append(networkNames, network.Name)
}

state, err := flowkit.Init(loader, crypto.ECDSA_P256, crypto.SHA3_256)
if err != nil {
return nil, fmt.Errorf("could not initialize flowkit state %w", err)
}
testnetClient := flowkit.NewFlowkit(state, config.TestnetNetwork, gwt, logger)
mainnetClient := flowkit.NewFlowkit(state, config.MainnetNetwork, gwm, logger)
// add core contracts to deployed contracts
cc := contracts.GetCoreContracts()
deployedContracts := make([]Contract, 0)
for contractName, c := range cc {
contract := Contract{
Contract: contractName,
Networks: []Network{
{Network: config.MainnetNetwork.Name, Address: c[config.MainnetNetwork.Name]},
{Network: config.TestnetNetwork.Name, Address: c[config.TestnetNetwork.Name]},
{Network: config.EmulatorNetwork.Name, Address: c[config.EmulatorNetwork.Name]},
},
}
deployedContracts = append(deployedContracts, contract)
}
// allow user contracts to override core contracts
for contractInfo, networks := range contractInfos {
contract := Contract{
Contract: contractInfo,
Networks: make([]Network, 0),
var nets []Network
for network, address := range c {
// if network is in user defined networks then add to deployed contracts
if isItemInArray(network, networkNames) {
addr := flow.HexToAddress(address)
nets = append(nets, Network{
Network: network,
Address: addr.HexWithPrefix(),
})
}
}
for network, address := range networks {
addr := flow.HexToAddress(address)
contract.Networks = append(contract.Networks, Network{
Network: network,
Address: "0x" + addr.Hex(),
})
if len(nets) > 0 {
contract := Contract{
Contract: contractName,
Networks: nets,
}
deployedContracts = append(deployedContracts, contract)
}
deployedContracts = append(deployedContracts, contract)
}

deployedContracts = mergeContractsAndInfos(deployedContracts, contractInfos)

return &Generator{
deployedContracts: deployedContracts,
testnetClient: testnetClient,
mainnetClient: mainnetClient,
clients: clients,
template: &InteractionTemplate{},
}, nil
}
Expand Down Expand Up @@ -194,6 +189,15 @@ func (g Generator) processDependencies(ctx context.Context, program *ast.Program
return nil
}

func getNetworkClient(networkName string, clients []*flowkit.Flowkit) *flowkit.Flowkit {
for _, client := range clients {
if client.Network().Name == networkName {
return client
}
}
return nil
}

func (g *Generator) generateDependenceInfo(ctx context.Context, contractName string) ([]Network, error) {
// only support string import syntax
contractNetworks := g.LookupImportContractInfo(contractName)
Expand All @@ -206,12 +210,7 @@ func (g *Generator) generateDependenceInfo(ctx context.Context, contractName str
Network: n.Network,
Address: n.Address,
}
var flowkit *flowkit.Flowkit
if n.Network == config.MainnetNetwork.Name && g.mainnetClient != nil {
flowkit = g.mainnetClient
} else if n.Network == config.TestnetNetwork.Name && g.testnetClient != nil {
flowkit = g.testnetClient
}
flowkit := getNetworkClient(n.Network, g.clients)
if n.DependencyPinBlockHeight == 0 && flowkit != nil {
block, _ := flowkit.Gateway().GetLatestBlock()
height := block.Height
Expand Down Expand Up @@ -305,3 +304,47 @@ func getAddressImports(code []byte, name string) []string {
}
return deps
}

// Helper function to merge ContractInfos into []Contract and add missing contracts
func mergeContractsAndInfos(contracts []Contract, infos ContractInfos) []Contract {
// Track existing contracts for quick lookup
existingContracts := make(map[string]int)
for i, contract := range contracts {
existingContracts[contract.Contract] = i

if info, exists := infos[contract.Contract]; exists {
// Create a map to track existing networks for duplicate check
existingNetworks := make(map[string]bool)
for _, network := range contract.Networks {
existingNetworks[network.Network] = true
}

// Iterate over the networks in the ContractInfos
for network, address := range info {
if !existingNetworks[network] {
// If the network doesn't exist in the contract, add it
contracts[i].Networks = append(contracts[i].Networks, Network{
Network: network,
Address: address,
})
}
}
}
}

// Add contracts from infos that don't exist in the current contracts array
for contractName, networks := range infos {
if _, exists := existingContracts[contractName]; !exists {
newContract := Contract{Contract: contractName}
for network, address := range networks {
newContract.Networks = append(newContract.Networks, Network{
Network: network,
Address: address,
})
}
contracts = append(contracts, newContract)
}
}

return contracts
}
6 changes: 0 additions & 6 deletions internal/v1_1/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ func TestHelloScript(t *testing.T) {

generator := Generator{
deployedContracts: contracts,
testnetClient: nil,
mainnetClient: nil,
}

assert := assert.New(t)
Expand Down Expand Up @@ -86,8 +84,6 @@ func TestTransactionValue(t *testing.T) {

generator := Generator{
deployedContracts: contracts,
testnetClient: nil,
mainnetClient: nil,
}
assert := assert.New(t)
code := `
Expand Down Expand Up @@ -142,8 +138,6 @@ func TestTransferFlowTransaction(t *testing.T) {
// fill in top level dependencies for the generator
generator := &Generator{
deployedContracts: cs,
testnetClient: nil,
mainnetClient: nil,
}
assert := assert.New(t)
code := `
Expand Down
9 changes: 9 additions & 0 deletions internal/v1_1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,12 @@ func ExtractContractName(importStr string) (string, error) {

return "", fmt.Errorf("no contract name found in string")
}

func isItemInArray[T comparable](item T, slice []T) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}

0 comments on commit 7d4fc6a

Please sign in to comment.