Repository: onflow/flow-cli
Pull request #1188 (2023-09-06 21:33:41)

Filter fee events
Closes: https://github.com/onflow/flow-cli/issues/1151

## Description
 - filter out "FeeEvent" and "FlowToken" events by default.
 - Add new included `fee-events` flag so users can get all events including the fee events.
 - Added two new tests to test filtering events
 - Updated transactions get command include flags help
______

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
- [ ] 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
- [ ] Added appropriate labels



Patch:
diff --git a/flowkit/config/json/account.go b/flowkit/config/json/account.go
index 7708ee35..cbf444a0 100644
--- a/flowkit/config/json/account.go
+++ b/flowkit/config/json/account.go
@@ -476,9 +476,9 @@ func (a account) JSONSchema() *jsonschema.Schema {
 			},
 		},
 		Definitions: map[string]*jsonschema.Schema{
-			"simpleAccount": jsonschema.Reflect(simpleAccount{}),
-			"advancedAccount": jsonschema.Reflect(advancedAccount{}),
-			"simpleAccountPre022": jsonschema.Reflect(simpleAccountPre022{}),
+			"simpleAccount":        jsonschema.Reflect(simpleAccount{}),
+			"advancedAccount":      jsonschema.Reflect(advancedAccount{}),
+			"simpleAccountPre022":  jsonschema.Reflect(simpleAccountPre022{}),
 			"advanceAccountPre022": jsonschema.Reflect(advanceAccountPre022{}),
 		},
 	}
diff --git a/flowkit/config/json/network.go b/flowkit/config/json/network.go
index 1c2fa1c9..4654c155 100644
--- a/flowkit/config/json/network.go
+++ b/flowkit/config/json/network.go
@@ -166,4 +166,4 @@ func (j jsonNetwork) JSONSchema() *jsonschema.Schema {
 			"advancedNetwork": jsonschema.Reflect(advancedNetwork{}),
 		},
 	}
-}
\ No newline at end of file
+}
diff --git a/flowkit/config/json/schema.go b/flowkit/config/json/schema.go
index 8445f654..6aaa6be0 100644
--- a/flowkit/config/json/schema.go
+++ b/flowkit/config/json/schema.go
@@ -29,12 +29,12 @@ func GenerateSchema() *jsonschema.Schema {
 	// This is necessary because the jsonschema library does not support
 	// definitions in nested schemas and is a workaround
 	var moveDefinitions func(*jsonschema.Schema)
-	moveDefinitions = func (s *jsonschema.Schema) {
+	moveDefinitions = func(s *jsonschema.Schema) {
 		for k, v := range s.Definitions {
 			schema.Definitions[k] = v
 			moveDefinitions(v)
 		}
-		if (s != schema) {
+		if s != schema {
 			s.Definitions = nil
 		}
 	}
diff --git a/flowkit/state.go b/flowkit/state.go
index 1fc05c51..57967348 100644
--- a/flowkit/state.go
+++ b/flowkit/state.go
@@ -213,7 +213,7 @@ func (p *State) AliasesForNetwork(network config.Network) project.LocationAliase
 		if contract.IsAliased() && contract.Aliases.ByNetwork(network.Name) != nil {
 			alias := contract.Aliases.ByNetwork(network.Name).Address.String()
 			aliases[filepath.Clean(contract.Location)] = alias // alias for import by file location
-			aliases[contract.Name] = alias                 // alias for import by name
+			aliases[contract.Name] = alias                     // alias for import by name
 		}
 	}
 
diff --git a/internal/transactions/get.go b/internal/transactions/get.go
index dc662a12..d2379fc0 100644
--- a/internal/transactions/get.go
+++ b/internal/transactions/get.go
@@ -32,7 +32,7 @@ import (
 
 type flagsGet struct {
 	Sealed  bool     `default:"true" flag:"sealed" info:"Wait for a sealed result"`
-	Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload."`
+	Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload, fee-events."`
 	Exclude []string `default:"" flag:"exclude" info:"Fields to exclude from the output. Valid values: events."`
 }
 
diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go
index 9a2f1641..ed9f0e3c 100644
--- a/internal/transactions/transactions.go
+++ b/internal/transactions/transactions.go
@@ -22,6 +22,7 @@ import (
 	"bytes"
 	"encoding/json"
 	"fmt"
+	"strings"
 
 	"github.com/onflow/flow-go-sdk"
 	"github.com/spf13/cobra"
@@ -90,6 +91,8 @@ func (r *transactionResult) JSON() any {
 func (r *transactionResult) String() string {
 	var b bytes.Buffer
 	writer := util.CreateTabWriter(&b)
+	const feeEventsCountAppended = 3
+	const feeDeductedEvent = "FeesDeducted"
 
 	if r.result != nil {
 		_, _ = fmt.Fprintf(writer, "Block ID\t%s\n", r.result.BlockID)
@@ -153,6 +156,16 @@ func (r *transactionResult) String() string {
 			Events: r.result.Events,
 		}
 
+		if r.result != nil && e.Events != nil && !command.ContainsFlag(r.include, "fee-events") {
+			for _, event := range e.Events {
+				if strings.Contains(event.Type, feeDeductedEvent) {
+					// if fee event are present remove them
+					e.Events = e.Events[:len(e.Events)-feeEventsCountAppended]
+					break
+				}
+			}
+		}
+
 		eventsOutput := e.String()
 		if eventsOutput == "" {
 			eventsOutput = "None"
@@ -184,6 +197,10 @@ func (r *transactionResult) String() string {
 		_, _ = fmt.Fprint(writer, "\n\nPayload (hidden, use --include payload)")
 	}
 
+	if !command.ContainsFlag(r.include, "fee-events") && !command.ContainsFlag(r.exclude, "events") {
+		_, _ = fmt.Fprint(writer, "\n\nFee Events (hidden, use --include fee-events)")
+	}
+
 	_ = writer.Flush()
 	return b.String()
 }


Test patch:
diff --git a/internal/transactions/transactions_test.go b/internal/transactions/transactions_test.go
index ef49d676..ff5a6f5b 100644
--- a/internal/transactions/transactions_test.go
+++ b/internal/transactions/transactions_test.go
@@ -306,6 +306,24 @@ func Test_Result(t *testing.T) {
 	)
 	event.Payload = []byte("mock_payload")
 
+	withdrawEvent := tests.NewEvent(
+		1,
+		"A.1654653399040a61.FlowToken.TokensWithdrawn",
+		[]cadence.Field{{Type: cadence.StringType{}, Identifier: "bar"}},
+		[]cadence.Value{cadence.NewInt(1)},
+	)
+	depositEvent := tests.NewEvent(
+		2,
+		"A.1654653399040a61.FlowToken.TokensDeposited",
+		[]cadence.Field{{Type: cadence.StringType{}, Identifier: "bar"}},
+		[]cadence.Value{cadence.NewInt(1)},
+	)
+	feeEvent := tests.NewEvent(
+		3,
+		"A.f919ee77447b7497.FlowFees.FeesDeducted",
+		[]cadence.Field{{Type: cadence.StringType{}, Identifier: "bar"}},
+		[]cadence.Value{cadence.NewInt(1)},
+	)
 	txResult := &flow.TransactionResult{
 		Status:      flow.TransactionStatusSealed,
 		Error:       nil,
@@ -314,6 +332,13 @@ func Test_Result(t *testing.T) {
 		BlockHeight: 1,
 	}
 
+	txResultFeeEvents := &flow.TransactionResult{
+		Status:      flow.TransactionStatusSealed,
+		Error:       nil,
+		Events:      []flow.Event{*event, *withdrawEvent, *depositEvent, *feeEvent},
+		BlockID:     flow.HexToID("7aa74143741c1c3b837d389fcffa7a5e251b67b4ffef6d6887b40cd9c803f537"),
+		BlockHeight: 1,
+	}
 	t.Run("Success with no result", func(t *testing.T) {
 		result := transactionResult{tx: tx}
 
@@ -333,7 +358,9 @@ Signatures (minimized, use --include signatures)
 
 Code (hidden, use --include code)
 
-Payload (hidden, use --include payload)`, "\n"), result.String())
+Payload (hidden, use --include payload)
+
+Fee Events (hidden, use --include fee-events)`, "\n"), result.String())
 
 		assert.Equal(t, map[string]any{
 			"authorizers": "[]",
@@ -374,7 +401,9 @@ Events:
 
 Code (hidden, use --include code)
 
-Payload (hidden, use --include payload)`, output.OkEmoji()), "\n")
+Payload (hidden, use --include payload)
+
+Fee Events (hidden, use --include fee-events)`, output.OkEmoji()), "\n")
 
 		assert.Equal(t, expectedString, result.String())
 
@@ -395,4 +424,91 @@ Payload (hidden, use --include payload)`, output.OkEmoji()), "\n")
 			"status":  "SEALED",
 		}, result.JSON())
 	})
+
+	t.Run("Result without fee events", func(t *testing.T) {
+		result := transactionResult{tx: tx, result: txResultFeeEvents}
+
+		assert.Equal(t, strings.TrimPrefix(`
+Block ID	7aa74143741c1c3b837d389fcffa7a5e251b67b4ffef6d6887b40cd9c803f537
+Block Height	1
+Status		✅ SEALED
+ID		e913d1f3e431c7df49c99845bea9ebff9db11bbf25d507b9ad0fad45652d515f
+Payer		0000000000000002
+Authorizers	[]
+
+Proposal Key:	
+    Address	0000000000000001
+    Index	0
+    Sequence	1
+
+Payload Signature 0: 0000000000000001
+Envelope Signature 0: 0000000000000001
+Signatures (minimized, use --include signatures)
+
+Events:		 
+    Index	0
+    Type	A.foo
+    Tx ID	0000000000000000000000000000000000000000000000000000000000000000
+    Values
+		- bar (String): 1 
+
+
+
+Code (hidden, use --include code)
+
+Payload (hidden, use --include payload)
+
+Fee Events (hidden, use --include fee-events)`, "\n"), result.String())
+	})
+	t.Run("Result with fee events", func(t *testing.T) {
+		result := transactionResult{tx: tx, result: txResultFeeEvents, include: []string{"fee-events"}}
+
+		assert.Equal(t, strings.TrimPrefix(`
+Block ID	7aa74143741c1c3b837d389fcffa7a5e251b67b4ffef6d6887b40cd9c803f537
+Block Height	1
+Status		✅ SEALED
+ID		e913d1f3e431c7df49c99845bea9ebff9db11bbf25d507b9ad0fad45652d515f
+Payer		0000000000000002
+Authorizers	[]
+
+Proposal Key:	
+    Address	0000000000000001
+    Index	0
+    Sequence	1
+
+Payload Signature 0: 0000000000000001
+Envelope Signature 0: 0000000000000001
+Signatures (minimized, use --include signatures)
+
+Events:		 
+    Index	0
+    Type	A.foo
+    Tx ID	0000000000000000000000000000000000000000000000000000000000000000
+    Values
+		- bar (String): 1 
+
+    Index	1
+    Type	A.1654653399040a61.FlowToken.TokensWithdrawn
+    Tx ID	0000000000000000000000000000000000000000000000000000000000000000
+    Values
+		- bar (String): 1 
+
+    Index	2
+    Type	A.1654653399040a61.FlowToken.TokensDeposited
+    Tx ID	0000000000000000000000000000000000000000000000000000000000000000
+    Values
+		- bar (String): 1 
+
+    Index	3
+    Type	A.f919ee77447b7497.FlowFees.FeesDeducted
+    Tx ID	0000000000000000000000000000000000000000000000000000000000000000
+    Values
+		- bar (String): 1 
+
+
+
+Code (hidden, use --include code)
+
+Payload (hidden, use --include payload)`, "\n"), result.String())
+	})
 }