From d8d65c4e4a7d3d112a7e44619c4d09bd5613d539 Mon Sep 17 00:00:00 2001 From: jinoosss <112360739+jinoosss@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:06:42 +0900 Subject: [PATCH] feat: Add the success attribute to a transaction (#35) --- serve/graph/generated.go | 70 ++++++++++++++++++- serve/graph/model/models_gen.go | 3 + serve/graph/model/transaction.go | 4 ++ .../schema/filter/transaction_filter.graphql | 6 ++ serve/graph/schema/types/transaction.graphql | 5 ++ serve/graph/transaction_filter.go | 13 ++++ 6 files changed, 100 insertions(+), 1 deletion(-) diff --git a/serve/graph/generated.go b/serve/graph/generated.go index a72f4ee6..ee954d85 100644 --- a/serve/graph/generated.go +++ b/serve/graph/generated.go @@ -114,6 +114,7 @@ type ComplexityRoot struct { Index func(childComplexity int) int Memo func(childComplexity int) int Messages func(childComplexity int) int + Success func(childComplexity int) int } TransactionMessage struct { @@ -440,6 +441,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Transaction.Messages(childComplexity), true + case "Transaction.success": + if e.complexity.Transaction.Success == nil { + break + } + + return e.complexity.Transaction.Success(childComplexity), true + case "TransactionMessage.route": if e.complexity.TransactionMessage.Route == nil { break @@ -1851,6 +1859,8 @@ func (ec *executionContext) fieldContext_Query_transactions(ctx context.Context, return ec.fieldContext_Transaction_index(ctx, field) case "hash": return ec.fieldContext_Transaction_hash(ctx, field) + case "success": + return ec.fieldContext_Transaction_success(ctx, field) case "block_height": return ec.fieldContext_Transaction_block_height(ctx, field) case "gas_wanted": @@ -2175,6 +2185,8 @@ func (ec *executionContext) fieldContext_Subscription_transactions(ctx context.C return ec.fieldContext_Transaction_index(ctx, field) case "hash": return ec.fieldContext_Transaction_hash(ctx, field) + case "success": + return ec.fieldContext_Transaction_success(ctx, field) case "block_height": return ec.fieldContext_Transaction_block_height(ctx, field) case "gas_wanted": @@ -2374,6 +2386,50 @@ func (ec *executionContext) fieldContext_Transaction_hash(ctx context.Context, f return fc, nil } +func (ec *executionContext) _Transaction_success(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_success(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Success(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_success(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Transaction_block_height(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Transaction_block_height(ctx, field) if err != nil { @@ -5059,7 +5115,7 @@ func (ec *executionContext) unmarshalInputTransactionFilter(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"from_block_height", "to_block_height", "from_index", "to_index", "from_gas_wanted", "to_gas_wanted", "from_gas_used", "to_gas_used", "hash", "message", "memo"} + fieldsInOrder := [...]string{"from_block_height", "to_block_height", "from_index", "to_index", "from_gas_wanted", "to_gas_wanted", "from_gas_used", "to_gas_used", "hash", "message", "memo", "success"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -5143,6 +5199,13 @@ func (ec *executionContext) unmarshalInputTransactionFilter(ctx context.Context, return it, err } it.Memo = data + case "success": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("success")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + if err != nil { + return it, err + } + it.Success = data } } @@ -5795,6 +5858,11 @@ func (ec *executionContext) _Transaction(ctx context.Context, sel ast.SelectionS if out.Values[i] == graphql.Null { out.Invalids++ } + case "success": + out.Values[i] = ec._Transaction_success(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "block_height": out.Values[i] = ec._Transaction_block_height(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/serve/graph/model/models_gen.go b/serve/graph/model/models_gen.go index 20bd7425..c0dd8d84 100644 --- a/serve/graph/model/models_gen.go +++ b/serve/graph/model/models_gen.go @@ -240,6 +240,9 @@ type TransactionFilter struct { // `memo` can be utilized to find or distinguish transactions. // For example, when trading a specific exchange, you would utilize the memo field of the transaction. Memo *string `json:"memo,omitempty"` + // `success` is whether the transaction was successful or not. + // `success` enables you to filter between successful and unsuccessful transactions. + Success *bool `json:"success,omitempty"` } // Transaction's message to filter Transactions. diff --git a/serve/graph/model/transaction.go b/serve/graph/model/transaction.go index 77e80aff..9d8b733c 100644 --- a/serve/graph/model/transaction.go +++ b/serve/graph/model/transaction.go @@ -47,6 +47,10 @@ func (t *Transaction) BlockHeight() int { return int(t.txResult.Height) } +func (t *Transaction) Success() bool { + return t.txResult.Response.IsOK() +} + func (t *Transaction) GasWanted() int { return int(t.txResult.Response.GasWanted) } diff --git a/serve/graph/schema/filter/transaction_filter.graphql b/serve/graph/schema/filter/transaction_filter.graphql index d9b8aeb2..1b06e48b 100644 --- a/serve/graph/schema/filter/transaction_filter.graphql +++ b/serve/graph/schema/filter/transaction_filter.graphql @@ -59,6 +59,12 @@ input TransactionFilter { For example, when trading a specific exchange, you would utilize the memo field of the transaction. """ memo: String + + """ + `success` is whether the transaction was successful or not. + `success` enables you to filter between successful and unsuccessful transactions. + """ + success: Boolean } """ diff --git a/serve/graph/schema/types/transaction.graphql b/serve/graph/schema/types/transaction.graphql index 7dc2f291..d1d2b0ea 100644 --- a/serve/graph/schema/types/transaction.graphql +++ b/serve/graph/schema/types/transaction.graphql @@ -12,6 +12,11 @@ type Transaction { """ hash: String! + """ + The success can determine whether the transaction succeeded or failed. + """ + success: Boolean! + """ The height of the Block in which this Transaction is included. Links the Transaction to its containing Block. """ diff --git a/serve/graph/transaction_filter.go b/serve/graph/transaction_filter.go index eaee6a67..ade92265 100644 --- a/serve/graph/transaction_filter.go +++ b/serve/graph/transaction_filter.go @@ -10,6 +10,10 @@ import ( // `FilteredTransactionBy` checks for conditions in GasUsed, GasWanted, Memo, and Message. // By default, the condition is only checked if the input parameter exists. func FilteredTransactionBy(tx *model.Transaction, filter model.TransactionFilter) bool { + if !filteredTransactionBySuccess(tx, filter.Success) { + return false + } + if !filteredTransactionByGasUsed(tx, filter.FromGasUsed, filter.ToGasUsed) { return false } @@ -39,6 +43,15 @@ func FilteredTransactionBy(tx *model.Transaction, filter model.TransactionFilter return true } +// `filteredTransactionBySuccess` will check the success or failure results of the transaction. +func filteredTransactionBySuccess(tx *model.Transaction, success *bool) bool { + if success == nil { + return true + } + + return deref(success) == tx.Success() +} + // `filteredAmountBy` checks a token represented as a string() // against a range of amount and a denomination. func filteredAmountBy(amountStr string, amountInput *model.AmountInput) bool {