github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/articulate/log.go (about)

     1  package articulate
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/abi"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    10  )
    11  
    12  // ArticulateLog articulates a log by attaching the Articulated log structure if the ABI is found.
    13  func (abiCache *AbiCache) ArticulateLog(log *types.Log) error {
    14  	if found, err := articulateLogFromMap(log, &abiCache.AbiMap); err != nil {
    15  		return err
    16  
    17  	} else if found != nil {
    18  		log.ArticulatedLog = found
    19  		return nil
    20  
    21  	} else {
    22  		address := log.Address
    23  		if !abiCache.loadedMap.GetValue(address) && !abiCache.skipMap.GetValue(address) {
    24  			if err = abi.LoadAbi(abiCache.Conn, address, &abiCache.AbiMap); err != nil {
    25  				abiCache.skipMap.SetValue(address, true)
    26  				if !errors.Is(err, rpc.ErrNotAContract) {
    27  					// Not being a contract is not an error because we want to articulate the input in case it's a message
    28  					return err
    29  				}
    30  			} else {
    31  				abiCache.loadedMap.SetValue(address, true)
    32  			}
    33  		}
    34  
    35  		if !abiCache.skipMap.GetValue(address) {
    36  			if log.ArticulatedLog, err = articulateLogFromMap(log, &abiCache.AbiMap); err != nil {
    37  				return err
    38  			}
    39  		}
    40  		return nil
    41  	}
    42  }
    43  
    44  func articulateLogFromMap(log *types.Log, abiMap *abi.SelectorSyncMap) (*types.Function, error) {
    45  	if len(log.Topics) < 1 {
    46  		return nil, nil
    47  	}
    48  
    49  	// Try to articulate the log using some common events
    50  	artLog := findCommonEvent(log)
    51  
    52  	// If we couldn't, then try to find the event in `abiMap`
    53  	if artLog == nil {
    54  		selector := "0x" + hex.EncodeToString(log.Topics[0].Bytes())
    55  		if found := abiMap.GetValue(selector); found != nil {
    56  			artLog = found.Clone()
    57  		} else {
    58  			// If artLog is still nil, we don't have ABI for this event
    59  			return nil, nil
    60  		}
    61  	}
    62  
    63  	abiEvent, err := artLog.GetAbiEvent()
    64  	if err != nil {
    65  		return artLog, err
    66  	}
    67  	data := log.Data
    68  	if len(log.Data) > 1 {
    69  		data = log.Data[2:]
    70  	}
    71  
    72  	if err = articulateArguments(abiEvent.Inputs, data, log.Topics, artLog.Inputs); err != nil {
    73  		return artLog, err
    74  	}
    75  
    76  	return artLog, nil
    77  }
    78  
    79  func findCommonEvent(log *types.Log) *types.Function {
    80  	if artLog := parseTransferEvent(log); artLog != nil {
    81  		return artLog
    82  
    83  	} else if artLog = parseEnsTransferEvent(log); artLog != nil {
    84  		return artLog
    85  
    86  	} else if artLog = parseApprovalEvent(log); artLog != nil {
    87  		return artLog
    88  	}
    89  
    90  	return nil
    91  }