github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/avalanche/evm.go (about)

     1  package avalanche
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"strings"
     7  
     8  	"github.com/ava-labs/coreth/core/types"
     9  	"github.com/ava-labs/coreth/ethclient"
    10  	"github.com/ava-labs/coreth/interfaces"
    11  	"github.com/ava-labs/coreth/rpc"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/trezor/blockbook/bchain"
    14  )
    15  
    16  // AvalancheClient wraps a client to implement the EVMClient interface
    17  type AvalancheClient struct {
    18  	ethclient.Client
    19  }
    20  
    21  // HeaderByNumber returns a block header that implements the EVMHeader interface
    22  func (c *AvalancheClient) HeaderByNumber(ctx context.Context, number *big.Int) (bchain.EVMHeader, error) {
    23  	h, err := c.Client.HeaderByNumber(ctx, number)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	return &AvalancheHeader{Header: h}, nil
    29  }
    30  
    31  // EstimateGas returns the current estimated gas cost for executing a transaction
    32  func (c *AvalancheClient) EstimateGas(ctx context.Context, msg interface{}) (uint64, error) {
    33  	return c.Client.EstimateGas(ctx, msg.(interfaces.CallMsg))
    34  }
    35  
    36  // BalanceAt returns the balance for the given account at a specific block, or latest known block if no block number is provided
    37  func (c *AvalancheClient) BalanceAt(ctx context.Context, addrDesc bchain.AddressDescriptor, blockNumber *big.Int) (*big.Int, error) {
    38  	return c.Client.BalanceAt(ctx, common.BytesToAddress(addrDesc), blockNumber)
    39  }
    40  
    41  // NonceAt returns the nonce for the given account at a specific block, or latest known block if no block number is provided
    42  func (c *AvalancheClient) NonceAt(ctx context.Context, addrDesc bchain.AddressDescriptor, blockNumber *big.Int) (uint64, error) {
    43  	return c.Client.NonceAt(ctx, common.BytesToAddress(addrDesc), blockNumber)
    44  }
    45  
    46  // AvalancheRPCClient wraps an rpc client to implement the EVMRPCClient interface
    47  type AvalancheRPCClient struct {
    48  	*rpc.Client
    49  }
    50  
    51  // EthSubscribe subscribes to events and returns a client subscription that implements the EVMClientSubscription interface
    52  func (c *AvalancheRPCClient) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (bchain.EVMClientSubscription, error) {
    53  	sub, err := c.Client.EthSubscribe(ctx, channel, args...)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return &AvalancheClientSubscription{ClientSubscription: sub}, nil
    59  }
    60  
    61  // CallContext performs a JSON-RPC call with the given arguments
    62  func (c *AvalancheRPCClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
    63  	err := c.Client.CallContext(ctx, result, method, args...)
    64  	// unfinalized data cannot be queried error returned when trying to query a block height greater than last finalized block
    65  	// do not throw rpc error and instead treat as ErrBlockNotFound
    66  	// https://docs.avax.network/quickstart/exchanges/integrate-exchange-with-avalanche#determining-finality
    67  	if err != nil && !strings.Contains(err.Error(), "cannot query unfinalized data") {
    68  		return err
    69  	}
    70  	return nil
    71  }
    72  
    73  // AvalancheHeader wraps a block header to implement the EVMHeader interface
    74  type AvalancheHeader struct {
    75  	*types.Header
    76  }
    77  
    78  // Hash returns the block hash as a hex string
    79  func (h *AvalancheHeader) Hash() string {
    80  	return h.Header.Hash().Hex()
    81  }
    82  
    83  // Number returns the block number
    84  func (h *AvalancheHeader) Number() *big.Int {
    85  	return h.Header.Number
    86  }
    87  
    88  // Difficulty returns the block difficulty
    89  func (h *AvalancheHeader) Difficulty() *big.Int {
    90  	return h.Header.Difficulty
    91  }
    92  
    93  // AvalancheHash wraps a transaction hash to implement the EVMHash interface
    94  type AvalancheHash struct {
    95  	common.Hash
    96  }
    97  
    98  // AvalancheClientSubscription wraps a client subcription to implement the EVMClientSubscription interface
    99  type AvalancheClientSubscription struct {
   100  	*rpc.ClientSubscription
   101  }
   102  
   103  // AvalancheNewBlock wraps a block header channel to implement the EVMNewBlockSubscriber interface
   104  type AvalancheNewBlock struct {
   105  	channel chan *types.Header
   106  }
   107  
   108  // Channel returns the underlying channel as an empty interface
   109  func (s *AvalancheNewBlock) Channel() interface{} {
   110  	return s.channel
   111  }
   112  
   113  // Read from the underlying channel and return a block header that implements the EVMHeader interface
   114  func (s *AvalancheNewBlock) Read() (bchain.EVMHeader, bool) {
   115  	h, ok := <-s.channel
   116  	return &AvalancheHeader{Header: h}, ok
   117  }
   118  
   119  // Close the underlying channel
   120  func (s *AvalancheNewBlock) Close() {
   121  	close(s.channel)
   122  }
   123  
   124  // AvalancheNewTx wraps a transaction hash channel to conform with the EVMNewTxSubscriber interface
   125  type AvalancheNewTx struct {
   126  	channel chan common.Hash
   127  }
   128  
   129  // Channel returns the underlying channel as an empty interface
   130  func (s *AvalancheNewTx) Channel() interface{} {
   131  	return s.channel
   132  }
   133  
   134  // Read from the underlying channel and return a transaction hash that implements the EVMHash interface
   135  func (s *AvalancheNewTx) Read() (bchain.EVMHash, bool) {
   136  	h, ok := <-s.channel
   137  	return &AvalancheHash{Hash: h}, ok
   138  }
   139  
   140  // Close the underlying channel
   141  func (s *AvalancheNewTx) Close() {
   142  	close(s.channel)
   143  }