github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/internal/tokens/handle_show.go (about)

     1  package tokensPkg
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/tslib"
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    11  	"github.com/ethereum/go-ethereum"
    12  )
    13  
    14  func (opts *TokensOptions) HandleShow(rCtx *output.RenderCtx) error {
    15  	chain := opts.Globals.Chain
    16  	tokenAddr := base.HexToAddress(opts.Addrs[0])
    17  
    18  	fetchData := func(modelChan chan types.Modeler, errorChan chan error) {
    19  		for _, address := range opts.Addrs[1:] {
    20  			addr := base.HexToAddress(address)
    21  			currentBn := base.Blknum(0)
    22  			currentTs := base.Timestamp(0)
    23  			for _, br := range opts.BlockIds {
    24  				blockNums, err := br.ResolveBlocks(chain)
    25  				if err != nil {
    26  					errorChan <- err
    27  					if errors.Is(err, ethereum.NotFound) {
    28  						continue
    29  					}
    30  					rCtx.Cancel()
    31  					return
    32  				}
    33  
    34  				for _, bn := range blockNums {
    35  					if balance, err := opts.Conn.GetBalanceAtToken(tokenAddr, addr, fmt.Sprintf("0x%x", bn)); balance == nil {
    36  						errorChan <- err
    37  					} else {
    38  						if opts.Globals.Verbose {
    39  							if bn == 0 || bn != currentBn {
    40  								currentTs, _ = tslib.FromBnToTs(chain, bn)
    41  							}
    42  							currentBn = bn
    43  						}
    44  						s := &types.Token{
    45  							Holder:      addr,
    46  							Address:     tokenAddr,
    47  							Balance:     *balance,
    48  							BlockNumber: bn,
    49  							Timestamp:   currentTs,
    50  							TokenType:   types.TokenErc20,
    51  						}
    52  						modelChan <- s
    53  					}
    54  				}
    55  			}
    56  		}
    57  	}
    58  
    59  	extraOpts := map[string]any{
    60  		"parts":     []string{"all_held"},
    61  		"loadNames": true,
    62  	}
    63  
    64  	return output.StreamMany(rCtx, fetchData, opts.Globals.OutputOptsWithExtra(extraOpts))
    65  }
    66  
    67  // TODO: NOTE THIS - DOES IT STILL WORK THIS WAY?
    68  // } else if (by_acct) {
    69  //     // All user-provided addresses are assumed to be tokens, except the last one which is the holder
    70  //     holders.push_back(addrs[addrs.size() - 1]);
    71  //     CAddressArray::iterator it;
    72  //     it = prev(addrs.end());
    73  //     addrs.erase(it);
    74  //     for (auto addr : addrs) {
    75  //         if (!isContractAt(addr, latestBlock))
    76  //             errors.push_back("Address '" + addr + "' is not a token contract.");
    77  //         else
    78  //             tokens.push_back(addr);
    79  //     }