Repository: onflow/flow-cli (go)

Issue:
SDK can't parse transactions with functions
### Instructions

When  I try to send a transaction with util functions like below, the CLI panics


```cadence
pub fun dummy(_ address: Address): Void {}

transaction {
  prepare(acct: AuthAccount) {}
}
```

### Problem

When I try to send the transaction, I run into this error:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x4883510]

goroutine 1 [running]:
github.com/onflow/flow-cli/pkg/flowkit.(*Transaction).AddAuthorizers(0xc000a21488, {0xc000a1da48, 0x1, 0xc000486900})
        github.com/onflow/flow-cli/pkg/flowkit/transaction.go:294 +0x90
github.com/onflow/flow-cli/pkg/flowkit/services.(*Transactions).Build(0xc000263b00, {0xf8, 0xd6, 0xe0, 0x58, 0x6b, 0xa, 0x20, 0xc7}, {0xc000a1da48, ...}, ...)
        github.com/onflow/flow-cli/pkg/flowkit/services/transactions.go:141 +0x40a
github.com/onflow/flow-cli/pkg/flowkit/services.(*Transactions).Send(0xc000263b00, 0xc00012a9b0, {0xc000994000, 0x69f, 0x89f}, {0x7ffeefbfe77f, 0x31}, 0xc0002861f8, {0x625cad0, 0x0, ...}, ...)
        github.com/onflow/flow-cli/pkg/flowkit/services/transactions.go:220 +0x1c6
github.com/onflow/flow-cli/internal/transactions.send({0xc0000f1240, 0x2, 0x4}, {0x5695d20, 0xc000584f60}, {{0x0, 0x0}, {0x52b31d0, 0x4}, {0x0, ...}, ...}, ...)
        github.com/onflow/flow-cli/internal/transactions/send.go:89 +0x312
github.com/onflow/flow-cli/internal/command.Command.AddToParent.func1(0x6215380, {0xc0000f1240, 0x2, 0x4})
        github.com/onflow/flow-cli/internal/command/command.go:116 +0x315
github.com/spf13/cobra.(*Command).execute(0x6215380, {0xc00003c0a0, 0x4, 0x4})
        github.com/spf13/cobra@v1.2.1/command.go:860 +0x5f8
github.com/spf13/cobra.(*Command).ExecuteC(0xc0003b1180)
        github.com/spf13/cobra@v1.2.1/command.go:974 +0x3bc
github.com/spf13/cobra.(*Command).Execute(...)
        github.com/spf13/cobra@v1.2.1/command.go:902
main.main()
        github.com/onflow/flow-cli/cmd/flow/main.go:76 +0x465
```

### Steps to Reproduce

#### 1. Pass ✅ 

This is okay.

```cadence
transaction {
  prepare(acct: AuthAccount) {}
}
```

#### 2.  Panics 💥 

```cadence
pub fun dummy(_ address: Address): Void {}

transaction {
  prepare(acct: AuthAccount) {}
}
```

### Acceptance Criteria

<if any>

### Context

This happens in these components

* Flow CLI
* VS Code extensions

Sorry, if this is expected behavior.
When I send the transaction directry to the API, I don't get any errors. Thus, I think this only happens in the Go SDK and the VS Code extension.

Pull request:
Bugfix transaction multiple function declaration
Closes #437

## Description
This PR fixes a bug where a transaction includes multiple function declarations due to nature of `SoleTransactionDeclaration`.

Example of such transaction is:
```
pub fun dummy(_ address: Address): Void {}

transaction {
  prepare(acct: AuthAccount) {}
}
```

______

For contributor use:

- [x] Targeted PR against `master` branch
- [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work
- [x] Code follows the [standards mentioned here](https://github.com/onflow/flow-cli/blob/master/CONTRIBUTING.md#styleguides)
- [x] Updated relevant documentation
- [x] Re-reviewed `Files changed` in the Github PR explorer
- [x] Added appropriate labels


Patch:
diff --git a/pkg/flowkit/transaction.go b/pkg/flowkit/transaction.go
index 30d03b2d..dd67e009 100644
--- a/pkg/flowkit/transaction.go
+++ b/pkg/flowkit/transaction.go
@@ -23,15 +23,13 @@ import (
 	"encoding/hex"
 	"fmt"
 
+	"github.com/onflow/cadence"
+	jsoncdc "github.com/onflow/cadence/encoding/json"
+	"github.com/onflow/cadence/runtime/ast"
 	"github.com/onflow/cadence/runtime/cmd"
 	"github.com/onflow/cadence/runtime/common"
-
-	jsoncdc "github.com/onflow/cadence/encoding/json"
-
-	"github.com/onflow/flow-go-sdk/templates"
-
-	"github.com/onflow/cadence"
 	"github.com/onflow/flow-go-sdk"
+	"github.com/onflow/flow-go-sdk/templates"
 )
 
 const maxGasLimit uint64 = 9999
@@ -291,12 +289,20 @@ func (t *Transaction) AddAuthorizers(authorizers []flow.Address) (*Transaction,
 	)
 
 	// get authorizers param list if exists
-	if program.SoleTransactionDeclaration().Prepare != nil {
-		requiredAuths := program.SoleTransactionDeclaration().
-			Prepare.
-			FunctionDeclaration.
-			ParameterList.
-			Parameters
+	if len(program.TransactionDeclarations()) == 1 {
+		declaration := program.TransactionDeclarations()[0]
+		requiredAuths := make([]*ast.Parameter, 0)
+
+		// if prepare block is missing set default authorizers to empty
+		if declaration.Prepare == nil {
+			authorizers = nil
+		} else { // if prepare block is present get authorizers
+			requiredAuths = declaration.
+				Prepare.
+				FunctionDeclaration.
+				ParameterList.
+				Parameters
+		}
 
 		if len(requiredAuths) != len(authorizers) {
 			return nil, fmt.Errorf(
@@ -305,6 +311,8 @@ func (t *Transaction) AddAuthorizers(authorizers []flow.Address) (*Transaction,
 				len(authorizers),
 			)
 		}
+	} else {
+		return nil, fmt.Errorf("can only support one transaction declaration per file")
 	}
 
 	for _, authorizer := range authorizers {


Test patch:
diff --git a/pkg/flowkit/services/transactions_test.go b/pkg/flowkit/services/transactions_test.go
index 5792ca64..3842a273 100644
--- a/pkg/flowkit/services/transactions_test.go
+++ b/pkg/flowkit/services/transactions_test.go
@@ -180,7 +180,7 @@ func TestTransactions_Integration(t *testing.T) {
 			ftx := tx.FlowTransaction()
 			assert.Equal(t, ftx.Script, i.code)
 			assert.Equal(t, ftx.Payer, i.payer)
-			assert.Equal(t, ftx.Authorizers, i.auth)
+			assert.Equal(t, len(ftx.Authorizers), 0) // make sure authorizers weren't added as tx input doesn't require them
 			assert.Equal(t, ftx.ProposalKey.Address, i.prop)
 			assert.Equal(t, ftx.ProposalKey.KeyIndex, i.index)
 		}
@@ -429,4 +429,26 @@ func TestTransactions_Integration(t *testing.T) {
 		assert.Nil(t, txr.Error)
 		assert.Equal(t, txr.Status, flow.TransactionStatusSealed)
 	})
+
+	t.Run("Send transaction with multiple func declaration", func(t *testing.T) {
+		t.Parallel()
+		state, s := setupIntegration()
+		setupAccounts(state, s)
+
+		a, _ := state.Accounts().ByName("Alice")
+
+		tx, txr, err := s.Transactions.Send(
+			a,
+			tests.TransactionMultipleDeclarations.Source,
+			tests.TransactionMultipleDeclarations.Filename,
+			1000,
+			nil,
+			"",
+		)
+		assert.NoError(t, err)
+		assert.Equal(t, tx.Payer.String(), a.Address().String())
+		assert.Equal(t, tx.ProposalKey.KeyIndex, a.Key().Index())
+		assert.Nil(t, txr.Error)
+		assert.Equal(t, txr.Status, flow.TransactionStatusSealed)
+	})
 }
diff --git a/tests/resources.go b/tests/resources.go
index d432d092..1d4a8bf6 100644
--- a/tests/resources.go
+++ b/tests/resources.go
@@ -200,6 +200,17 @@ var TransactionTwoAuth = resource{
 	`),
 }
 
+var TransactionMultipleDeclarations = resource{
+	Filename: "transactionMultipleDec.cdc",
+	Source: []byte(`
+		pub fun dummy(_ address: Address): Void {}
+
+		transaction() {
+			prepare(authorizer: AuthAccount) {}
+		}
+	`),
+}
+
 var ScriptWithError = resource{
 	Filename: "scriptError.cdc",
 	Source: []byte(`