diff --git a/internal/common/log.go b/internal/common/log.go index 96d7bee..f0fef4f 100644 --- a/internal/common/log.go +++ b/internal/common/log.go @@ -252,13 +252,17 @@ func (l *Log) Serialize() LogModel { } func (l *DecodedLog) Serialize() DecodedLogModel { + // Convert big numbers to strings in both indexed and non-indexed parameters + indexedParams := ConvertBigNumbersToString(l.Decoded.IndexedParams).(map[string]interface{}) + nonIndexedParams := ConvertBigNumbersToString(l.Decoded.NonIndexedParams).(map[string]interface{}) + return DecodedLogModel{ LogModel: l.Log.Serialize(), Decoded: DecodedLogDataModel{ Name: l.Decoded.Name, Signature: l.Decoded.Signature, - IndexedParams: l.Decoded.IndexedParams, - NonIndexedParams: l.Decoded.NonIndexedParams, + IndexedParams: indexedParams, + NonIndexedParams: nonIndexedParams, }, } } diff --git a/internal/common/transaction.go b/internal/common/transaction.go index 51ed0d3..5321091 100644 --- a/internal/common/transaction.go +++ b/internal/common/transaction.go @@ -229,12 +229,15 @@ func (t *Transaction) Serialize() TransactionModel { } func (t *DecodedTransaction) Serialize() DecodedTransactionModel { + // Convert big numbers to strings in the decoded inputs + decodedInputs := ConvertBigNumbersToString(t.Decoded.Inputs).(map[string]interface{}) + return DecodedTransactionModel{ TransactionModel: t.Transaction.Serialize(), Decoded: DecodedTransactionDataModel{ Name: t.Decoded.Name, Signature: t.Decoded.Signature, - Inputs: t.Decoded.Inputs, + Inputs: decodedInputs, }, } } diff --git a/internal/common/utils.go b/internal/common/utils.go index c5b21b3..a3b35bc 100644 --- a/internal/common/utils.go +++ b/internal/common/utils.go @@ -5,7 +5,6 @@ import ( "math/big" "regexp" "strings" - "unicode" ) func BigIntSliceToChunks(values []*big.Int, chunkSize int) [][]*big.Int { @@ -23,143 +22,6 @@ func BigIntSliceToChunks(values []*big.Int, chunkSize int) [][]*big.Int { return chunks } -// StripPayload removes parameter names, 'indexed' keywords, -// and extra whitespaces from a Solidity function or event signature. -func StripPayload(signature string) string { - // Find the index of the first '(' and last ')' - start := strings.Index(signature, "(") - end := strings.LastIndex(signature, ")") - if start == -1 || end == -1 || end <= start { - // Return the original signature if it doesn't match the expected pattern - return signature - } - - functionName := strings.TrimSpace(signature[:start]) - paramsStr := signature[start+1 : end] - - // Parse parameters - strippedParams := parseParameters(paramsStr) - - // Reconstruct the cleaned-up signature - strippedSignature := fmt.Sprintf("%s(%s)", functionName, strings.Join(strippedParams, ",")) - return strippedSignature -} - -// parseParameters parses the parameter string and returns a slice of cleaned-up parameter types -func parseParameters(paramsStr string) []string { - var params []string - var currentParam strings.Builder - bracketDepth := 0 - var inType bool // Indicates if we are currently parsing a type - - runes := []rune(paramsStr) - i := 0 - for i < len(runes) { - char := runes[i] - switch char { - case '(', '[', '{': - bracketDepth++ - inType = true - currentParam.WriteRune(char) - i++ - case ')', ']', '}': - bracketDepth-- - currentParam.WriteRune(char) - i++ - case ',': - if bracketDepth == 0 { - // End of current parameter - paramType := cleanType(currentParam.String()) - if paramType != "" { - params = append(params, paramType) - } - currentParam.Reset() - inType = false - i++ - } else { - currentParam.WriteRune(char) - i++ - } - case ' ': - if inType { - currentParam.WriteRune(char) - } - i++ - default: - // Check if the word is a keyword to ignore - if unicode.IsLetter(char) { - wordStart := i - for i < len(runes) && (unicode.IsLetter(runes[i]) || unicode.IsDigit(runes[i])) { - i++ - } - word := string(runes[wordStart:i]) - - // Ignore 'indexed' and parameter names - if isType(word) { - inType = true - currentParam.WriteString(word) - } else if word == "indexed" { - // Skip 'indexed' - inType = false - } else { - // Ignore parameter names - if inType { - // If we are in the middle of parsing a type and encounter a parameter name, skip it - inType = false - } - } - } else { - if inType { - currentParam.WriteRune(char) - } - i++ - } - } - } - - // Add the last parameter - if currentParam.Len() > 0 { - paramType := cleanType(currentParam.String()) - if paramType != "" { - params = append(params, paramType) - } - } - - return params -} - -// cleanType cleans up a parameter type string by removing extra spaces and 'tuple' keyword -func cleanType(param string) string { - // Remove 'tuple' keyword - param = strings.ReplaceAll(param, "tuple", "") - // Remove 'indexed' keyword - param = strings.ReplaceAll(param, "indexed", "") - // Remove any parameter names (already handled in parsing) - param = strings.TrimSpace(param) - // Remove extra whitespaces - param = strings.Join(strings.Fields(param), "") - return param -} - -// isType checks if a word is a Solidity type -func isType(word string) bool { - if strings.HasPrefix(word, "uint") || strings.HasPrefix(word, "int") { - return true - } - types := map[string]bool{ - "address": true, - "bool": true, - "string": true, - "bytes": true, - "fixed": true, - "ufixed": true, - "function": true, - // Add other types as needed - } - - return types[word] -} - var allowedFunctions = map[string]struct{}{ "sum": {}, "count": {}, @@ -217,3 +79,35 @@ func ValidateQuery(query string) error { return nil } + +func ConvertBigNumbersToString(data interface{}) interface{} { + switch v := data.(type) { + case map[string]interface{}: + for key, value := range v { + v[key] = ConvertBigNumbersToString(value) + } + return v + case []interface{}: + for i, value := range v { + v[i] = ConvertBigNumbersToString(value) + } + return v + case []*big.Int: + result := make([]string, len(v)) + for i, num := range v { + if num == nil { + result[i] = "0" + } else { + result[i] = num.String() + } + } + return result + case *big.Int: + if v == nil { + return "0" + } + return v.String() + default: + return v + } +}