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 }