synapsecns/sanguine

View on GitHub
ethergo/backends/base/trace.go

Summary

Maintainability
A
25 mins
Test Coverage
package base

import (
    "fmt"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    "github.com/synapsecns/sanguine/ethergo/parser/tracely"
)

// getTransactionLabels gets the labels for all contracts used in this transaction.
// if a list of labels cannot be obtained using a trace all registered contracts will be returned.
//
// TODO: this should be able to work with a simulated backend but can't right now.
// returns address->label.
// nolint: cyclop, ineffassign, staticcheck, revive, wastedassign
func (b *Backend) getTransactionLabelMap(tx *types.Transaction, from common.Address) (res map[common.Address]string) {
    b.verifiedMux.RLock()
    defer b.verifiedMux.RUnlock()

    res = map[common.Address]string{}
    txResult, err := tracely.GetTxResult(b.RPCAddress(), tx.Hash().String())
    if err != nil {
        logger.Warnf("could not get tx result: %v", err)
    }

    res[from] = "sender"

    // if we can't get the tx result, we'll just return all the verified contracts.
    if err != nil || b.RPCAddress() == "" {
        for _, contract := range b.verifiedContracts {
            res[contract.Address()] = contract.ContractName()
        }
        return res
    }

    if tx.To() != nil {
        if contract, ok := b.verifiedContracts[*tx.To()]; ok {
            res[*tx.To()] = contract.ContractName()
        }
    }

    // walk through each frame of the transaction and get the contract address
    for _, frame := range txResult {
        stackRes := map[string]string{}
        switch frame.Op {
        case "CALL":
            stackRes, err = tracely.ParseCall(frame)
        case "DELEGATECALL", "STATICCALL":
            stackRes, err = tracely.ParseDelegateCall(frame)
        case "REVERT":
            stackRes, err = tracely.ParseRevert(frame)
        }

        addr := common.HexToAddress(stackRes["addr"])

        if contract, ok := b.verifiedContracts[addr]; ok {
            res[addr] = contract.ContractName()
        }

        for _, addie := range frame.Stack {
            stackAddie, ok := addie.(string)
            if !ok {
                continue
            }

            address := common.HexToAddress(stackAddie)

            if contract, ok := b.verifiedContracts[address]; ok {
                res[address] = contract.ContractName()
            }
        }
    }

    return res
}

// addCastLabels adds the labels for all contracts used in this transaction to the cast.
func (b *Backend) addCastLabels(tx *types.Transaction, from common.Address) (res string) {
    labels := b.getTransactionLabelMap(tx, from)
    for address, name := range labels {
        res += fmt.Sprintf("--label %s:%s ", address.String(), name)
    }

    // remove trailing comma
    if len(res) > 0 {
        res = res[:len(res)-1]
    }
    return res
}