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

     1  package abi
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/binary"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"io/fs"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    17  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors"
    18  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
    19  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
    20  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    21  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
    22  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    23  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
    24  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk"
    25  	"github.com/ethereum/go-ethereum/accounts/abi"
    26  )
    27  
    28  // LoadAbi tries to load ABI from any source (local file, cache, download from 3rd party)
    29  func LoadAbi(conn *rpc.Connection, address base.Address, abiMap *SelectorSyncMap) error {
    30  	err := conn.IsContractAtLatest(address)
    31  	if err != nil {
    32  		if errors.Is(err, rpc.ErrNotAContract) && !utils.IsFuzzing() {
    33  			logger.Progress(logger.IsTerminal(), fmt.Sprintf("Skipping EOA %s", colors.Cyan+address.Hex()+colors.Off))
    34  		}
    35  		return err
    36  	}
    37  
    38  	if err = loadAbiFromAddress(conn, address, abiMap); err != nil {
    39  		if !os.IsNotExist(err) && err != io.EOF {
    40  			return fmt.Errorf("while reading %s ABI file: %w", address, err)
    41  		}
    42  
    43  		return abiMap.downloadAbi(conn.Chain, address)
    44  	}
    45  
    46  	return nil
    47  }
    48  
    49  // Where to find know ABI files
    50  // var knownAbiSubdirectories = []string{
    51  // 	"known-000", "known-005", "known-010", "known-015",
    52  // }
    53  
    54  func fromJson(reader io.Reader, abiMap *SelectorSyncMap) (err error) {
    55  	// Compute encodings, signatures and parse file
    56  	loadedAbi, err := abi.JSON(reader)
    57  	if err != nil {
    58  		return
    59  	}
    60  
    61  	for _, method := range loadedAbi.Methods {
    62  		function := types.FunctionFromAbiMethod(&method)
    63  		abiMap.SetValue(function.Encoding, function)
    64  	}
    65  
    66  	for _, ethEvent := range loadedAbi.Events {
    67  		event := types.FunctionFromAbiEvent(&ethEvent)
    68  		abiMap.SetValue(event.Encoding, event)
    69  	}
    70  
    71  	return
    72  }
    73  
    74  // loadAbiFromKnownFile loads data from _known_ ABI file, which has encodings and
    75  // signatures.
    76  func loadAbiFromKnownFile(filePath string, abiMap *SelectorSyncMap) (err error) {
    77  	f, err := os.OpenFile(filePath, os.O_RDONLY, 0)
    78  	if err != nil {
    79  		return
    80  	}
    81  
    82  	// We still need abi.Method and abi.Event, so will just use fromJson
    83  	return fromJson(f, abiMap)
    84  }
    85  
    86  // readCString reads cString structure from reader. It has different signature than
    87  // the rest of `read*` functions in this package, to ease reading values into
    88  // other structs' fields
    89  func readCString(reader *bufio.Reader, str *cString) (err error) {
    90  	err = binary.Read(reader, binary.LittleEndian, &str.size)
    91  	if err != nil {
    92  		return
    93  	}
    94  
    95  	str.content = make([]byte, str.size)
    96  	err = binary.Read(reader, binary.LittleEndian, str.content)
    97  	if err != nil {
    98  		return
    99  	}
   100  	return
   101  }
   102  
   103  func readCacheHeader(reader *bufio.Reader, target *cacheHeader) (err error) {
   104  	err = binary.Read(reader, binary.LittleEndian, &target.deleted)
   105  	if err != nil {
   106  		return
   107  	}
   108  
   109  	err = binary.Read(reader, binary.LittleEndian, &target.schema)
   110  	if err != nil {
   111  		return
   112  	}
   113  
   114  	err = binary.Read(reader, binary.LittleEndian, &target.showing)
   115  	if err != nil {
   116  		return
   117  	}
   118  
   119  	err = readCString(reader, &target.className)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	return
   125  }
   126  
   127  func readAddress(reader *bufio.Reader, target *base.Address) (err error) {
   128  	str := &cString{}
   129  	err = readCString(reader, str)
   130  	if err != nil {
   131  		return
   132  	}
   133  	addr := base.HexToAddress(string(str.content))
   134  	*target = addr
   135  	return
   136  }
   137  
   138  type arrayItem interface {
   139  	~string |
   140  		base.Hash |
   141  		base.Address |
   142  		types.Parameter |
   143  		types.Function
   144  }
   145  
   146  func writeArray[Item arrayItem](
   147  	writer *bufio.Writer,
   148  	items []Item,
   149  	writeFn func(*bufio.Writer, *Item) (err error),
   150  ) (err error) {
   151  	itemCount := uint64(len(items))
   152  	err = binary.Write(writer, binary.LittleEndian, itemCount)
   153  	if err != nil {
   154  		return
   155  	}
   156  
   157  	for _, item := range items {
   158  		err = writeFn(writer, &item)
   159  		if err != nil {
   160  			return
   161  		}
   162  	}
   163  	return
   164  }
   165  
   166  // readFromArray converts binary array into slice of type Item
   167  func readFromArray[Item arrayItem](
   168  	reader *bufio.Reader,
   169  	target *[]Item,
   170  	readValue func(reader *bufio.Reader) (*Item, error),
   171  ) (err error) {
   172  	// first, read item count
   173  	var itemCount uint64 = 0
   174  	err = binary.Read(reader, binary.LittleEndian, &itemCount)
   175  	if err != nil {
   176  		return
   177  	}
   178  
   179  	// make target large enough
   180  	*target = make([]Item, 0, itemCount)
   181  
   182  	// TODO: Just noting. If we knew the records in the array were fixed with (I think we
   183  	// TODO: may be able to know that), we can read and write the entire chunk of memory
   184  	// TODO: in one write (or read). It will almost certainly be faster. I don't think we do
   185  	// TODO: this in C++ code, but I always wanted to.
   186  	// read items
   187  	for i := 0; uint64(i) < itemCount; i++ {
   188  		item, readErr := readValue(reader)
   189  		if readErr != nil {
   190  			err = readErr
   191  			return
   192  		}
   193  
   194  		*target = append(*target, *item)
   195  	}
   196  
   197  	return
   198  }
   199  
   200  // readAbis reads ABI cache (known.bin)
   201  func readAbis(reader *bufio.Reader) (result []types.Function, err error) {
   202  	header := &cacheHeader{}
   203  	if err = readCacheHeader(reader, header); err != nil {
   204  		return
   205  	}
   206  	if err = validateHeader(header); err != nil {
   207  		return
   208  	}
   209  
   210  	// This address is always empty
   211  	var address base.Address
   212  	if err = readAddress(reader, &address); err != nil {
   213  		return
   214  	}
   215  	err = readFromArray(reader, &result, readFunction)
   216  
   217  	return
   218  }
   219  
   220  func readParameter(reader *bufio.Reader) (param *types.Parameter, err error) {
   221  	param = &types.Parameter{}
   222  	header := &cacheHeader{}
   223  	err = readCacheHeader(reader, header)
   224  	if err != nil {
   225  		return
   226  	}
   227  	err = validateHeader(header)
   228  	if err != nil {
   229  		return
   230  	}
   231  
   232  	err = readString(reader, &param.ParameterType)
   233  	if err != nil {
   234  		return
   235  	}
   236  
   237  	err = readString(reader, &param.Name)
   238  	if err != nil {
   239  		return
   240  	}
   241  
   242  	err = readString(reader, &param.StrDefault)
   243  	if err != nil {
   244  		return
   245  	}
   246  
   247  	var jsonValue string
   248  	if err = readString(reader, &jsonValue); err != nil {
   249  		return
   250  	}
   251  	if err = json.Unmarshal([]byte(jsonValue), &param.Value); err != nil {
   252  		return
   253  	}
   254  
   255  	err = binary.Read(reader, binary.LittleEndian, &param.Indexed)
   256  	if err != nil {
   257  		return
   258  	}
   259  
   260  	err = readString(reader, &param.InternalType)
   261  	if err != nil {
   262  		return
   263  	}
   264  
   265  	err = readFromArray(reader, &param.Components, readParameter)
   266  	if err != nil {
   267  		return
   268  	}
   269  
   270  	unused1 := false
   271  	err = binary.Read(reader, binary.LittleEndian, &unused1)
   272  	if err != nil {
   273  		return
   274  	}
   275  
   276  	unused2 := uint64(0)
   277  	err = binary.Read(reader, binary.LittleEndian, &unused2)
   278  	if err != nil {
   279  		return
   280  	}
   281  
   282  	return
   283  }
   284  
   285  // TODO: I don't think we want to hard code this version value here. We want to read it programmatically
   286  // TODO: from auto-generated code. There is a string called version.LibraryVersion that we can use
   287  // TODO: to calculate this value. We can add a function to the version package.
   288  var minimumCacheVersion = uint64(41000)
   289  
   290  func validateHeader(header *cacheHeader) error {
   291  	if header.schema < minimumCacheVersion {
   292  		return errors.New("invalid schema")
   293  	}
   294  	return nil
   295  }
   296  
   297  type cString struct {
   298  	size    uint64
   299  	content []byte
   300  }
   301  type cacheHeader struct {
   302  	deleted   uint64
   303  	schema    uint64
   304  	showing   uint64
   305  	className cString
   306  }
   307  
   308  func readString(reader *bufio.Reader, target *string) (err error) {
   309  	str := &cString{}
   310  	err = readCString(reader, str)
   311  	if err != nil {
   312  		return
   313  	}
   314  	s := string(str.content)
   315  	*target = s
   316  	return
   317  }
   318  
   319  func readFunction(reader *bufio.Reader) (function *types.Function, err error) {
   320  	function = &types.Function{}
   321  	header := &cacheHeader{}
   322  	err = readCacheHeader(reader, header)
   323  	if err != nil {
   324  		return
   325  	}
   326  	err = validateHeader(header)
   327  	if err != nil {
   328  		return
   329  	}
   330  
   331  	err = readString(reader, &function.Name)
   332  	if err != nil {
   333  		return
   334  	}
   335  
   336  	err = readString(reader, &function.FunctionType)
   337  	if err != nil {
   338  		return
   339  	}
   340  
   341  	var unused string
   342  	err = readString(reader, &unused)
   343  	if err != nil {
   344  		return
   345  	}
   346  
   347  	err = binary.Read(reader, binary.LittleEndian, &function.Anonymous)
   348  	if err != nil {
   349  		return
   350  	}
   351  
   352  	err = binary.Read(reader, binary.LittleEndian, &function.Constant)
   353  	if err != nil {
   354  		return
   355  	}
   356  
   357  	err = readString(reader, &function.StateMutability)
   358  	if err != nil {
   359  		return
   360  	}
   361  
   362  	err = readString(reader, &function.Signature)
   363  	if err != nil {
   364  		return
   365  	}
   366  
   367  	err = readString(reader, &function.Encoding)
   368  	if err != nil {
   369  		return
   370  	}
   371  
   372  	err = readFromArray(reader, &function.Inputs, readParameter)
   373  	if err != nil {
   374  		return
   375  	}
   376  
   377  	err = readFromArray(reader, &function.Outputs, readParameter)
   378  	if err != nil {
   379  		return
   380  	}
   381  
   382  	return
   383  }
   384  
   385  // getAbis reads all ABIs stored in the cache
   386  func getAbis(chain string) ([]types.Function, error) {
   387  	fullPath := filepath.Join(config.PathToCache(chain), walk.CacheTypeToFolder[walk.Cache_Abis], "known.bin")
   388  	if f, err := os.OpenFile(fullPath, os.O_RDONLY, 0); err != nil {
   389  		return nil, err
   390  
   391  	} else {
   392  		defer f.Close()
   393  		bufReader := bufio.NewReader(f)
   394  		abis, err := readAbis(bufReader)
   395  		if err != nil && !os.IsNotExist(err) {
   396  			// Remove the file (if it exists). We will re-try next time
   397  			os.Remove(fullPath)
   398  		}
   399  		return abis, err
   400  	}
   401  }
   402  
   403  // loadCache loads binary cache of known ABIs
   404  func loadCache(chain string, abiMap *SelectorSyncMap) (loaded bool) {
   405  	functions, cacheErr := getAbis(chain)
   406  	// We can ignore cache error
   407  	if cacheErr != nil {
   408  		return
   409  	}
   410  
   411  	for _, function := range functions {
   412  		function.Normalize()
   413  		abiMap.SetValue(function.Encoding, &function)
   414  	}
   415  
   416  	return true
   417  }
   418  
   419  func writeString(writer *bufio.Writer, str *string) (err error) {
   420  	err = binary.Write(writer, binary.LittleEndian, uint64(len(*str)))
   421  	if err != nil {
   422  		return
   423  	}
   424  	err = binary.Write(writer, binary.LittleEndian, []byte(*str))
   425  	if err != nil {
   426  		return
   427  	}
   428  	return
   429  }
   430  
   431  func writeDefaultHeader(writer *bufio.Writer, className string) (err error) {
   432  	err = binary.Write(writer, binary.LittleEndian, uint64(0))
   433  	if err != nil {
   434  		return
   435  	}
   436  	err = binary.Write(writer, binary.LittleEndian, uint64(41000))
   437  	if err != nil {
   438  		return
   439  	}
   440  	err = binary.Write(writer, binary.LittleEndian, uint64(1))
   441  	if err != nil {
   442  		return
   443  	}
   444  
   445  	err = writeString(writer, &className)
   446  	if err != nil {
   447  		return
   448  	}
   449  	return
   450  }
   451  
   452  func writeFunction(writer *bufio.Writer, function *types.Function) (err error) {
   453  	err = writeDefaultHeader(writer, "CFunction")
   454  	if err != nil {
   455  		return
   456  	}
   457  
   458  	err = writeString(writer, &function.Name)
   459  	if err != nil {
   460  		return
   461  	}
   462  
   463  	err = writeString(writer, &function.FunctionType)
   464  	if err != nil {
   465  		return
   466  	}
   467  
   468  	var unused string
   469  	err = writeString(writer, &unused)
   470  	if err != nil {
   471  		return
   472  	}
   473  
   474  	err = binary.Write(writer, binary.LittleEndian, &function.Anonymous)
   475  	if err != nil {
   476  		return
   477  	}
   478  
   479  	err = binary.Write(writer, binary.LittleEndian, &function.Constant)
   480  	if err != nil {
   481  		return
   482  	}
   483  
   484  	err = writeString(writer, &function.StateMutability)
   485  	if err != nil {
   486  		return
   487  	}
   488  
   489  	err = writeString(writer, &function.Signature)
   490  	if err != nil {
   491  		return
   492  	}
   493  
   494  	err = writeString(writer, &function.Encoding)
   495  	if err != nil {
   496  		return
   497  	}
   498  
   499  	err = writeArray(writer, function.Inputs, writeParameter)
   500  	if err != nil {
   501  		return
   502  	}
   503  
   504  	err = writeArray(writer, function.Outputs, writeParameter)
   505  	if err != nil {
   506  		return
   507  	}
   508  
   509  	return
   510  }
   511  
   512  func writeParameter(writer *bufio.Writer, param *types.Parameter) (err error) {
   513  	err = writeDefaultHeader(writer, "CParameter")
   514  	if err != nil {
   515  		return
   516  	}
   517  
   518  	err = writeString(writer, &param.ParameterType)
   519  	if err != nil {
   520  		return
   521  	}
   522  
   523  	err = writeString(writer, &param.Name)
   524  	if err != nil {
   525  		return
   526  	}
   527  
   528  	err = writeString(writer, &param.StrDefault)
   529  	if err != nil {
   530  		return
   531  	}
   532  
   533  	jsonValue, err := json.Marshal(&param.Value)
   534  	if err != nil {
   535  		return
   536  	}
   537  	strValue := string(jsonValue)
   538  	if err = writeString(writer, &strValue); err != nil {
   539  		return
   540  	}
   541  
   542  	err = binary.Write(writer, binary.LittleEndian, &param.Indexed)
   543  	if err != nil {
   544  		return
   545  	}
   546  
   547  	err = writeString(writer, &param.InternalType)
   548  	if err != nil {
   549  		return
   550  	}
   551  
   552  	err = writeArray(writer, param.Components, writeParameter)
   553  	if err != nil {
   554  		return
   555  	}
   556  
   557  	unused1 := false
   558  	err = binary.Write(writer, binary.LittleEndian, &unused1)
   559  	if err != nil {
   560  		return
   561  	}
   562  
   563  	unused2 := uint64(0)
   564  	err = binary.Write(writer, binary.LittleEndian, &unused2)
   565  	if err != nil {
   566  		return
   567  	}
   568  
   569  	return
   570  }
   571  
   572  func writeAddress(writer *bufio.Writer, address *base.Address) (err error) {
   573  	value := address.Hex()[:2] + strings.ToLower(address.Hex()[2:])
   574  	if value == "0x0000000000000000000000000000000000000000" {
   575  		value = "0x0"
   576  		return writeString(writer, &value)
   577  	}
   578  	return writeString(writer, &value)
   579  }
   580  
   581  // writeAbis writes ABI cache (known.bin)
   582  func writeAbis(writer *bufio.Writer, abis []types.Function) (err error) {
   583  	err = writeDefaultHeader(writer, "CAbi")
   584  	if err != nil {
   585  		return
   586  	}
   587  
   588  	// This address is always empty
   589  	address := base.Address{}
   590  	if err = writeAddress(writer, &address); err != nil {
   591  		return
   592  	}
   593  	err = writeArray(writer, abis, writeFunction)
   594  	return
   595  }
   596  
   597  // setAbis writes ABIs to the cache
   598  func setAbis(chain string, abis []types.Function) (err error) {
   599  	var abisFilePath = filepath.Join(walk.CacheTypeToFolder[walk.Cache_Abis], "known.bin")
   600  	buf := bytes.Buffer{}
   601  	writer := bufio.NewWriter(&buf)
   602  	if err = writeAbis(writer, abis); err != nil {
   603  		return err
   604  	}
   605  	if err = writer.Flush(); err != nil {
   606  		return err
   607  	}
   608  	reader := bytes.NewReader(buf.Bytes())
   609  	return save(chain, abisFilePath, reader)
   610  }
   611  
   612  // save writes contents of `content` Reader to a file
   613  func save(chain string, filePath string, content io.Reader) (err error) {
   614  	cacheDir := config.PathToCache(chain)
   615  	fullPath := filepath.Join(cacheDir, filePath)
   616  
   617  	var f *os.File
   618  	if file.FileExists(fullPath) {
   619  		// If file doesn't exist, we don't need a lock
   620  		f, err = os.OpenFile(fullPath, os.O_RDWR|os.O_CREATE, 0666)
   621  		if err != nil {
   622  			return
   623  		}
   624  		defer f.Close()
   625  	} else {
   626  		f, err = file.WaitOnLock(fullPath, file.DefaultOpenFlags)
   627  		if err != nil {
   628  			return
   629  		}
   630  		defer f.Close()
   631  		if err = file.Empty(f); err != nil {
   632  			return
   633  		}
   634  	}
   635  
   636  	_, err = io.Copy(f, content)
   637  	return
   638  }
   639  
   640  // LoadKnownAbis loads known ABI files into abiMap, refreshing binary cache if needed
   641  func (abiMap *SelectorSyncMap) LoadKnownAbis(chain string) (err error) {
   642  	isUpToDate := func(chain string) (bool, error) {
   643  		testFn := filepath.Join(config.PathToCache(chain), "abis/known.bin")
   644  		testDir := filepath.Join(config.PathToRootConfig(), "abis")
   645  		if cacheFile, err := os.Stat(testFn); os.IsNotExist(err) {
   646  			return false, nil
   647  
   648  		} else if err != nil {
   649  			return false, err
   650  
   651  		} else {
   652  			if newestFile, err := file.GetNewestInDirectory(testDir); err != nil {
   653  				return false, err
   654  			} else {
   655  				return cacheFile.ModTime().Unix() >= newestFile.ModTime().Unix(), nil
   656  			}
   657  		}
   658  	}
   659  
   660  	useCache, err := isUpToDate(chain)
   661  	if err != nil {
   662  		return
   663  	}
   664  
   665  	if useCache {
   666  		if loaded := loadCache(chain, abiMap); loaded {
   667  			return
   668  		}
   669  	}
   670  
   671  	paths, err := getKnownAbiPaths()
   672  	if err != nil {
   673  		return
   674  	}
   675  
   676  	for _, filePath := range paths {
   677  		loadErr := loadAbiFromKnownFile(filePath, abiMap)
   678  		if loadErr != nil {
   679  			return fmt.Errorf("%s: %w", filePath, loadErr)
   680  		}
   681  	}
   682  
   683  	toCache := abiMap.Values()
   684  	return setAbis(chain, toCache)
   685  }
   686  
   687  func getKnownAbiPaths() (filePaths []string, err error) {
   688  	knownDirPath := filepath.Join(config.PathToRootConfig(), "abis")
   689  	err = filepath.WalkDir(knownDirPath, func(path string, d fs.DirEntry, err error) error {
   690  		if err != nil {
   691  			return err
   692  		}
   693  
   694  		if d.IsDir() {
   695  			return nil
   696  		}
   697  		if filepath.Ext(d.Name()) != ".json" {
   698  			return nil
   699  		}
   700  		info, err := d.Info()
   701  		if err != nil {
   702  			return err
   703  		}
   704  		if info.Size() == 0 {
   705  			return nil
   706  		}
   707  
   708  		filePaths = append(filePaths, path)
   709  		return nil
   710  	})
   711  	return
   712  }
   713  
   714  // loadAbiFromAddress loads ABI from local file or cache
   715  func loadAbiFromAddress(conn *rpc.Connection, address base.Address, abiMap *SelectorSyncMap) error {
   716  	var err error
   717  	chain := conn.Chain
   718  	localFileName := address.Hex() + ".json"
   719  	localFile, err := os.OpenFile(localFileName, os.O_RDONLY, 0)
   720  	if os.IsNotExist(err) {
   721  		// There's no local file, so we try to load one from cache
   722  		loadedAbis, err := getAbi(chain, address)
   723  		if err != nil {
   724  			return err
   725  		}
   726  
   727  		for _, loadedAbi := range loadedAbis {
   728  			loadedAbi.Normalize()
   729  			abiMap.SetValue(loadedAbi.Encoding, &loadedAbi)
   730  		}
   731  
   732  		return nil
   733  	}
   734  	if err != nil {
   735  		// There was different error, we may want to report it
   736  		return err
   737  	}
   738  	defer localFile.Close()
   739  
   740  	// Local file found
   741  	if err = fromJson(localFile, abiMap); err != nil {
   742  		return err
   743  	}
   744  	// File is correct, cache it
   745  	if err = insertAbi(chain, address, localFile); err != nil {
   746  		return err
   747  	}
   748  
   749  	return err
   750  }
   751  
   752  // insertAbi copies file (e.g. opened local file) into cache
   753  func insertAbi(chain string, address base.Address, inputReader io.Reader) error {
   754  	fullPath := filepath.Join(config.PathToCache(chain), walk.CacheTypeToFolder[walk.Cache_Abis], address.Hex()+".json")
   755  	if file, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666); err != nil {
   756  		return err
   757  	} else {
   758  		defer file.Close()
   759  		if _, err = io.Copy(file, inputReader); err != nil {
   760  			return err
   761  		}
   762  		return nil
   763  	}
   764  }
   765  
   766  // getAbi returns single ABI per address. ABI-per-address are stored as JSON, not binary.
   767  func getAbi(chain string, address base.Address) (simpleAbis []types.Function, err error) {
   768  	filePath := filepath.Join(walk.CacheTypeToFolder[walk.Cache_Abis], address.Hex()+".json")
   769  	fullPath := filepath.Join(config.PathToCache(chain), filePath)
   770  	f, err := os.OpenFile(fullPath, os.O_RDONLY, 0)
   771  	if err != nil {
   772  		return
   773  	}
   774  	defer f.Close()
   775  
   776  	ethAbi, err := abi.JSON(f)
   777  	if err != nil {
   778  		return
   779  	}
   780  
   781  	functions := make([]types.Function, 0, len(ethAbi.Methods))
   782  	for _, method := range ethAbi.Methods {
   783  		functions = append(functions, *types.FunctionFromAbiMethod(&method))
   784  	}
   785  
   786  	events := make([]types.Function, 0, len(ethAbi.Events))
   787  	for _, event := range ethAbi.Events {
   788  		events = append(events, *types.FunctionFromAbiEvent(&event))
   789  	}
   790  
   791  	simpleAbis = append(functions, events...)
   792  	return
   793  }