Skip to content

Commit 6d1009b

Browse files
authored
Strip signature params (#118)
### TL;DR Added functionality to strip and normalize Solidity function and event signatures. ### What changed? - Introduced a new `StripPayload` function in `utils.go` to remove parameter names, 'indexed' keywords, and extra whitespaces from Solidity function or event signatures. - Implemented helper functions `parseParameters`, `cleanType`, and `isType` to support the signature stripping process. - Updated `GetLogsByContractAndSignature` and `GetTransactionsByContractAndSignature` handlers to use the new `StripPayload` function before processing requests. ### How to test? 1. Call the API endpoints for getting logs or transactions by contract and signature. 2. Use various Solidity function and event signatures, including those with parameter names, `indexed` keywords, and extra whitespaces. 3. Verify that the API correctly handles and matches these signatures, regardless of the extra information included. ### Why make this change? This change improves the flexibility and user-friendliness of the API. It allows users to query logs and transactions using more verbose Solidity signatures without requiring exact matches. This normalization process ensures that signatures with different formatting or additional information (like parameter names) are still correctly recognized and processed by the system.
2 parents 22b7991 + 6f0e94e commit 6d1009b

File tree

3 files changed

+160
-3
lines changed

3 files changed

+160
-3
lines changed

internal/common/utils.go

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package common
22

3-
import "math/big"
3+
import (
4+
"fmt"
5+
"math/big"
6+
"strings"
7+
"unicode"
8+
)
49

510
func BigIntSliceToChunks(values []*big.Int, chunkSize int) [][]*big.Int {
611
if chunkSize >= len(values) || chunkSize <= 0 {
@@ -16,3 +21,151 @@ func BigIntSliceToChunks(values []*big.Int, chunkSize int) [][]*big.Int {
1621
}
1722
return chunks
1823
}
24+
25+
// StripPayload removes parameter names, 'indexed' keywords,
26+
// and extra whitespaces from a Solidity function or event signature.
27+
func StripPayload(signature string) string {
28+
// Find the index of the first '(' and last ')'
29+
start := strings.Index(signature, "(")
30+
end := strings.LastIndex(signature, ")")
31+
if start == -1 || end == -1 || end <= start {
32+
// Return the original signature if it doesn't match the expected pattern
33+
return signature
34+
}
35+
36+
functionName := strings.TrimSpace(signature[:start])
37+
paramsStr := signature[start+1 : end]
38+
39+
// Parse parameters
40+
strippedParams := parseParameters(paramsStr)
41+
42+
// Reconstruct the cleaned-up signature
43+
strippedSignature := fmt.Sprintf("%s(%s)", functionName, strings.Join(strippedParams, ","))
44+
return strippedSignature
45+
}
46+
47+
// parseParameters parses the parameter string and returns a slice of cleaned-up parameter types
48+
func parseParameters(paramsStr string) []string {
49+
var params []string
50+
var currentParam strings.Builder
51+
bracketDepth := 0
52+
var inType bool // Indicates if we are currently parsing a type
53+
54+
runes := []rune(paramsStr)
55+
i := 0
56+
for i < len(runes) {
57+
char := runes[i]
58+
switch char {
59+
case '(', '[', '{':
60+
bracketDepth++
61+
inType = true
62+
currentParam.WriteRune(char)
63+
i++
64+
case ')', ']', '}':
65+
bracketDepth--
66+
currentParam.WriteRune(char)
67+
i++
68+
case ',':
69+
if bracketDepth == 0 {
70+
// End of current parameter
71+
paramType := cleanType(currentParam.String())
72+
if paramType != "" {
73+
params = append(params, paramType)
74+
}
75+
currentParam.Reset()
76+
inType = false
77+
i++
78+
} else {
79+
currentParam.WriteRune(char)
80+
i++
81+
}
82+
case ' ':
83+
if inType {
84+
currentParam.WriteRune(char)
85+
}
86+
i++
87+
default:
88+
// Check if the word is a keyword to ignore
89+
if unicode.IsLetter(char) {
90+
wordStart := i
91+
for i < len(runes) && (unicode.IsLetter(runes[i]) || unicode.IsDigit(runes[i])) {
92+
i++
93+
}
94+
word := string(runes[wordStart:i])
95+
96+
// Ignore 'indexed' and parameter names
97+
if isType(word) {
98+
inType = true
99+
currentParam.WriteString(word)
100+
} else if word == "indexed" {
101+
// Skip 'indexed'
102+
inType = false
103+
} else {
104+
// Ignore parameter names
105+
if inType {
106+
// If we are in the middle of parsing a type and encounter a parameter name, skip it
107+
inType = false
108+
}
109+
}
110+
} else {
111+
if inType {
112+
currentParam.WriteRune(char)
113+
}
114+
i++
115+
}
116+
}
117+
}
118+
119+
// Add the last parameter
120+
if currentParam.Len() > 0 {
121+
paramType := cleanType(currentParam.String())
122+
if paramType != "" {
123+
params = append(params, paramType)
124+
}
125+
}
126+
127+
return params
128+
}
129+
130+
// cleanType cleans up a parameter type string by removing extra spaces and 'tuple' keyword
131+
func cleanType(param string) string {
132+
// Remove 'tuple' keyword
133+
param = strings.ReplaceAll(param, "tuple", "")
134+
// Remove 'indexed' keyword
135+
param = strings.ReplaceAll(param, "indexed", "")
136+
// Remove any parameter names (already handled in parsing)
137+
param = strings.TrimSpace(param)
138+
// Remove extra whitespaces
139+
param = strings.Join(strings.Fields(param), "")
140+
return param
141+
}
142+
143+
// isType checks if a word is a Solidity type
144+
func isType(word string) bool {
145+
types := map[string]bool{
146+
"uint": true,
147+
"int": true,
148+
"uint8": true,
149+
"int8": true,
150+
"uint16": true,
151+
"int16": true,
152+
"uint32": true,
153+
"int32": true,
154+
"uint64": true,
155+
"int64": true,
156+
"uint128": true,
157+
"int128": true,
158+
"uint256": true,
159+
"int256": true,
160+
"address": true,
161+
"bool": true,
162+
"string": true,
163+
"bytes": true,
164+
"fixed": true,
165+
"ufixed": true,
166+
"function": true,
167+
// Add other types as needed
168+
}
169+
170+
return types[word]
171+
}

internal/handlers/logs_handlers.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/rs/zerolog/log"
1010
"github.com/thirdweb-dev/indexer/api"
1111
config "github.com/thirdweb-dev/indexer/configs"
12+
"github.com/thirdweb-dev/indexer/internal/common"
1213
"github.com/thirdweb-dev/indexer/internal/storage"
1314
)
1415

@@ -105,7 +106,8 @@ func GetLogsByContract(c *gin.Context) {
105106
func GetLogsByContractAndSignature(c *gin.Context) {
106107
contractAddress := c.Param("contract")
107108
eventSignature := c.Param("signature")
108-
handleLogsRequest(c, contractAddress, eventSignature)
109+
strippedSignature := common.StripPayload(eventSignature)
110+
handleLogsRequest(c, contractAddress, strippedSignature)
109111
}
110112

111113
func handleLogsRequest(c *gin.Context, contractAddress, signature string) {

internal/handlers/transactions_handlers.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/gin-gonic/gin"
88
"github.com/rs/zerolog/log"
99
"github.com/thirdweb-dev/indexer/api"
10+
"github.com/thirdweb-dev/indexer/internal/common"
1011
"github.com/thirdweb-dev/indexer/internal/rpc"
1112
"github.com/thirdweb-dev/indexer/internal/storage"
1213
)
@@ -107,7 +108,8 @@ func GetTransactionsByContract(c *gin.Context) {
107108
func GetTransactionsByContractAndSignature(c *gin.Context) {
108109
to := c.Param("to")
109110
signature := c.Param("signature")
110-
handleTransactionsRequest(c, to, signature)
111+
strippedSignature := common.StripPayload(signature)
112+
handleTransactionsRequest(c, to, strippedSignature)
111113
}
112114

113115
func handleTransactionsRequest(c *gin.Context, contractAddress, signature string) {

0 commit comments

Comments
 (0)