ethergo/parser/tracely/op.go
package tracely
import (
"encoding/hex"
"errors"
"fmt"
"github.com/DenrianWeiss/tracely/model"
"math/big"
"strconv"
"strings"
)
func GenSpace(c int) string {
return strings.Repeat(" ", c)
}
func BytesToInt(b []byte) (int64, error) {
hexE := hex.EncodeToString(b)
bI, ok := big.NewInt(0).SetString(hexE, 16)
if !ok {
return 0, errors.New("failed to convert bytes to int")
}
return int64(bI.Uint64()), nil
}
func ParseCall(step model.TraceStep) (map[string]string, error) {
result := make(map[string]string)
stack := GenerateStack(step.Stack)
memory := GenerateMemory(step.Memory)
gas := AccessStack(stack, 0)
addr := AccessStack(stack, 1)
value := AccessStack(stack, 2)
argsOffset := AccessStack(stack, 3)
argsLength := AccessStack(stack, 4)
// Get Args.
offset, err := BytesToInt(argsOffset)
if err != nil {
return nil, fmt.Errorf("failed to convert args offset to int: %w", err)
}
argLength, err := BytesToInt(argsLength)
if err != nil {
return nil, fmt.Errorf("failed to convert args length to int: %w", err)
}
arg := AccessMemory(memory, int(offset), int(argLength))
gasCast, err := BytesToInt(gas)
if err != nil {
return nil, fmt.Errorf("failed to convert gas to int: %w", err)
}
castValue, err := BytesToInt(value)
if err != nil {
return nil, fmt.Errorf("failed to convert value to int: %w", err)
}
result["gas"] = strconv.FormatUint(uint64(gasCast), 10)
result["addr"] = "0x" + hex.EncodeToString(addr)[24:]
result["value"] = strconv.FormatUint(uint64(castValue), 10)
result["arg"] = hex.EncodeToString(arg)
return result, nil
}
func ParseDelegateCall(step model.TraceStep) (map[string]string, error) {
result := make(map[string]string)
stack := GenerateStack(step.Stack)
memory := GenerateMemory(step.Memory)
gas := AccessStack(stack, 0)
addr := AccessStack(stack, 1)
argsOffset := AccessStack(stack, 2)
argsLength := AccessStack(stack, 3)
castArgOffset, err := BytesToInt(argsOffset)
if err != nil {
return nil, fmt.Errorf("failed to convert args offset to int: %w", err)
}
castArgLength, err := BytesToInt(argsLength)
if err != nil {
return nil, fmt.Errorf("failed to convert args length to int: %w", err)
}
castGas, err := BytesToInt(gas)
if err != nil {
return nil, fmt.Errorf("failed to convert gas to int: %w", err)
}
// Get Args.
arg := AccessMemory(memory, int(castArgOffset), int(castArgLength))
result["gas"] = strconv.FormatUint(uint64(castGas), 10)
result["addr"] = "0x" + hex.EncodeToString(addr)[24:]
result["arg"] = hex.EncodeToString(arg)
return result, nil
}
func ParseRevert(step model.TraceStep) (map[string]string, error) {
result := make(map[string]string)
stack := GenerateStack(step.Stack)
memory := GenerateMemory(step.Memory)
if len(stack) <= 2 {
return result, nil
}
offset := AccessStack(stack, 0)
length := AccessStack(stack, 1)
castLength, _ := BytesToInt(length)
if castLength == 0 {
return result, nil
}
castOffset, err := BytesToInt(offset)
if err != nil {
return nil, fmt.Errorf("failed to convert offset to int: %w", err)
}
reason := AccessMemory(memory, int(castOffset), int(castLength))
result["reason"] = string(reason)
return result, nil
}
func ParseReturn(step model.TraceStep) (map[string]string, error) {
r, err := ParseRevert(step)
if err != nil {
return nil, err
}
r["result"] = hex.EncodeToString([]byte(r["reason"]))
delete(r, "reason")
return r, nil
}
func PrintStep(step model.TraceStep) (err error) {
var pCall map[string]string
if step.Op == "CALL" {
pCall, err = ParseCall(step)
fmt.Printf("%sCALL address %s, gas %s, value %s, payload %s\n",
GenSpace((step.Depth-1)*2),
pCall["addr"],
pCall["gas"],
pCall["value"],
pCall["arg"])
} else if step.Op == "DELEGATECALL" || step.Op == "STATICCALL" {
pCall, err = ParseDelegateCall(step)
fmt.Printf("%s%s address %s, gas %s, payload %s\n",
GenSpace((step.Depth-1)*2),
step.Op,
pCall["addr"],
pCall["gas"],
pCall["arg"])
} else if step.Op == "REVERT" {
pCall, err = ParseRevert(step)
fmt.Printf("%s%s: %s\n",
GenSpace((step.Depth-1)*2),
step.Op,
pCall["reason"],
)
} else if step.Op == "RETURN" {
pCall, err = ParseReturn(step)
fmt.Printf("%s%s: %s\n",
GenSpace((step.Depth-1)*2),
step.Op,
pCall["result"],
)
} else {
fmt.Printf("%s%s\n", GenSpace((step.Depth-1)*2), step.Op)
}
if err != nil {
fmt.Println(err)
}
return
}