github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/rollup/client.go (about)

     1  package rollup
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/big"
     7  	"strconv"
     8  
     9  	"github.com/ethereum-optimism/optimism/l2geth/common"
    10  	"github.com/ethereum-optimism/optimism/l2geth/common/hexutil"
    11  	"github.com/ethereum-optimism/optimism/l2geth/core/types"
    12  	"github.com/ethereum-optimism/optimism/l2geth/crypto"
    13  	"github.com/go-resty/resty/v2"
    14  )
    15  
    16  // Constants that are used to compare against values in the deserialized JSON
    17  // fetched by the RollupClient
    18  const (
    19  	sequencer = "sequencer"
    20  	l1        = "l1"
    21  )
    22  
    23  // errElementNotFound represents the error case of the remote element not being
    24  // found. It applies to transactions, queue elements and batches
    25  var errElementNotFound = errors.New("element not found")
    26  
    27  // errHttpError represents the error case of when the remote server
    28  // returns a 400 or greater error
    29  var errHTTPError = errors.New("http error")
    30  
    31  // Batch represents the data structure that is submitted with
    32  // a series of transactions to layer one
    33  type Batch struct {
    34  	Index             uint64         `json:"index"`
    35  	Root              common.Hash    `json:"root,omitempty"`
    36  	Size              uint32         `json:"size,omitempty"`
    37  	PrevTotalElements uint32         `json:"prevTotalElements,omitempty"`
    38  	ExtraData         hexutil.Bytes  `json:"extraData,omitempty"`
    39  	BlockNumber       uint64         `json:"blockNumber"`
    40  	Timestamp         uint64         `json:"timestamp"`
    41  	Submitter         common.Address `json:"submitter"`
    42  }
    43  
    44  // EthContext represents the L1 EVM context that is injected into
    45  // the OVM at runtime. It is updated with each `enqueue` transaction
    46  // and needs to be fetched from a remote server to be updated when
    47  // too much time has passed between `enqueue` transactions.
    48  type EthContext struct {
    49  	BlockNumber uint64      `json:"blockNumber"`
    50  	BlockHash   common.Hash `json:"blockHash"`
    51  	Timestamp   uint64      `json:"timestamp"`
    52  }
    53  
    54  // SyncStatus represents the state of the remote server. The SyncService
    55  // does not want to begin syncing until the remote server has fully synced.
    56  type SyncStatus struct {
    57  	Syncing                      bool   `json:"syncing"`
    58  	HighestKnownTransactionIndex uint64 `json:"highestKnownTransactionIndex"`
    59  	CurrentTransactionIndex      uint64 `json:"currentTransactionIndex"`
    60  }
    61  
    62  // L1GasPrice represents the gas price of L1. It is used as part of the gas
    63  // estimatation logic.
    64  type L1GasPrice struct {
    65  	GasPrice string `json:"gasPrice"`
    66  }
    67  
    68  // transaction represents the return result of the remote server.
    69  // It either came from a batch or was replicated from the sequencer.
    70  type transaction struct {
    71  	Index       uint64          `json:"index"`
    72  	BatchIndex  uint64          `json:"batchIndex"`
    73  	BlockNumber uint64          `json:"blockNumber"`
    74  	Timestamp   uint64          `json:"timestamp"`
    75  	Value       *hexutil.Big    `json:"value"`
    76  	GasLimit    uint64          `json:"gasLimit,string"`
    77  	Target      common.Address  `json:"target"`
    78  	Origin      *common.Address `json:"origin"`
    79  	Data        hexutil.Bytes   `json:"data"`
    80  	QueueOrigin string          `json:"queueOrigin"`
    81  	QueueIndex  *uint64         `json:"queueIndex"`
    82  	Decoded     *decoded        `json:"decoded"`
    83  }
    84  
    85  // Enqueue represents an `enqueue` transaction or a L1 to L2 transaction.
    86  type Enqueue struct {
    87  	Index       *uint64         `json:"ctcIndex"`
    88  	Target      *common.Address `json:"target"`
    89  	Data        *hexutil.Bytes  `json:"data"`
    90  	GasLimit    *uint64         `json:"gasLimit,string"`
    91  	Origin      *common.Address `json:"origin"`
    92  	BlockNumber *uint64         `json:"blockNumber"`
    93  	Timestamp   *uint64         `json:"timestamp"`
    94  	QueueIndex  *uint64         `json:"index"`
    95  }
    96  
    97  // signature represents a secp256k1 ECDSA signature
    98  type signature struct {
    99  	R hexutil.Bytes `json:"r"`
   100  	S hexutil.Bytes `json:"s"`
   101  	V uint          `json:"v"`
   102  }
   103  
   104  // decoded represents the decoded transaction from the batch.
   105  // When this struct exists in other structs and is set to `nil`,
   106  // it means that the decoding failed.
   107  type decoded struct {
   108  	Signature signature       `json:"sig"`
   109  	Value     *hexutil.Big    `json:"value"`
   110  	GasLimit  uint64          `json:"gasLimit,string"`
   111  	GasPrice  uint64          `json:"gasPrice,string"`
   112  	Nonce     uint64          `json:"nonce,string"`
   113  	Target    *common.Address `json:"target"`
   114  	Data      hexutil.Bytes   `json:"data"`
   115  }
   116  
   117  // RollupClient is able to query for information
   118  // that is required by the SyncService
   119  type RollupClient interface {
   120  	GetEnqueue(index uint64) (*types.Transaction, error)
   121  	GetLatestEnqueue() (*types.Transaction, error)
   122  	GetLatestEnqueueIndex() (*uint64, error)
   123  	GetRawTransaction(uint64, Backend) (*TransactionResponse, error)
   124  	GetTransaction(uint64, Backend) (*types.Transaction, error)
   125  	GetLatestTransaction(Backend) (*types.Transaction, error)
   126  	GetLatestTransactionIndex(Backend) (*uint64, error)
   127  	GetEthContext(uint64) (*EthContext, error)
   128  	GetLatestEthContext() (*EthContext, error)
   129  	GetLastConfirmedEnqueue() (*types.Transaction, error)
   130  	GetLatestTransactionBatch() (*Batch, []*types.Transaction, error)
   131  	GetLatestTransactionBatchIndex() (*uint64, error)
   132  	GetTransactionBatch(uint64) (*Batch, []*types.Transaction, error)
   133  	SyncStatus(Backend) (*SyncStatus, error)
   134  }
   135  
   136  // Client is an HTTP based RollupClient
   137  type Client struct {
   138  	client  *resty.Client
   139  	chainID *big.Int
   140  }
   141  
   142  // TransactionResponse represents the response from the remote server when
   143  // querying transactions.
   144  type TransactionResponse struct {
   145  	Transaction *transaction `json:"transaction"`
   146  	Batch       *Batch       `json:"batch"`
   147  }
   148  
   149  // TransactionBatchResponse represents the response from the remote server
   150  // when querying batches.
   151  type TransactionBatchResponse struct {
   152  	Batch        *Batch         `json:"batch"`
   153  	Transactions []*transaction `json:"transactions"`
   154  }
   155  
   156  // NewClient create a new Client given a remote HTTP url and a chain id
   157  func NewClient(url string, chainID *big.Int) *Client {
   158  	client := resty.New()
   159  	client.SetHostURL(url)
   160  	client.SetHeader("User-Agent", "sequencer")
   161  	client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
   162  		statusCode := r.StatusCode()
   163  		if statusCode >= 400 {
   164  			method := r.Request.Method
   165  			url := r.Request.URL
   166  			return fmt.Errorf("%d cannot %s %s: %w", statusCode, method, url, errHTTPError)
   167  		}
   168  		return nil
   169  	})
   170  
   171  	return &Client{
   172  		client:  client,
   173  		chainID: chainID,
   174  	}
   175  }
   176  
   177  // GetEnqueue fetches an `enqueue` transaction by queue index
   178  func (c *Client) GetEnqueue(index uint64) (*types.Transaction, error) {
   179  	str := strconv.FormatUint(index, 10)
   180  	response, err := c.client.R().
   181  		SetPathParams(map[string]string{
   182  			"index": str,
   183  		}).
   184  		SetResult(&Enqueue{}).
   185  		Get("/enqueue/index/{index}")
   186  
   187  	if err != nil {
   188  		return nil, fmt.Errorf("cannot fetch enqueue: %w", err)
   189  	}
   190  	enqueue, ok := response.Result().(*Enqueue)
   191  	if !ok {
   192  		return nil, fmt.Errorf("Cannot fetch enqueue %d", index)
   193  	}
   194  	if enqueue == nil {
   195  		return nil, fmt.Errorf("Cannot deserialize enqueue %d", index)
   196  	}
   197  	tx, err := enqueueToTransaction(enqueue)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	return tx, nil
   202  }
   203  
   204  // enqueueToTransaction turns an Enqueue into a types.Transaction
   205  // so that it can be consumed by the SyncService
   206  func enqueueToTransaction(enqueue *Enqueue) (*types.Transaction, error) {
   207  	if enqueue == nil {
   208  		return nil, errElementNotFound
   209  	}
   210  	// When the queue index is nil, is means that the enqueue'd transaction
   211  	// does not exist.
   212  	if enqueue.QueueIndex == nil {
   213  		return nil, errElementNotFound
   214  	}
   215  	// The queue index is the nonce
   216  	nonce := *enqueue.QueueIndex
   217  
   218  	if enqueue.Target == nil {
   219  		return nil, errors.New("Target not found for enqueue tx")
   220  	}
   221  	target := *enqueue.Target
   222  
   223  	if enqueue.GasLimit == nil {
   224  		return nil, errors.New("Gas limit not found for enqueue tx")
   225  	}
   226  	gasLimit := *enqueue.GasLimit
   227  	if enqueue.Origin == nil {
   228  		return nil, errors.New("Origin not found for enqueue tx")
   229  	}
   230  	origin := *enqueue.Origin
   231  	if enqueue.BlockNumber == nil {
   232  		return nil, errors.New("Blocknumber not found for enqueue tx")
   233  	}
   234  	blockNumber := new(big.Int).SetUint64(*enqueue.BlockNumber)
   235  	if enqueue.Timestamp == nil {
   236  		return nil, errors.New("Timestamp not found for enqueue tx")
   237  	}
   238  	timestamp := *enqueue.Timestamp
   239  
   240  	if enqueue.Data == nil {
   241  		return nil, errors.New("Data not found for enqueue tx")
   242  	}
   243  	data := *enqueue.Data
   244  
   245  	// enqueue transactions have no value
   246  	value := big.NewInt(0)
   247  	tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)
   248  
   249  	// The index does not get a check as it is allowed to be nil in the context
   250  	// of an enqueue transaction that has yet to be included into the CTC
   251  	txMeta := types.NewTransactionMeta(
   252  		blockNumber,
   253  		timestamp,
   254  		&origin,
   255  		types.QueueOriginL1ToL2,
   256  		enqueue.Index,
   257  		enqueue.QueueIndex,
   258  		data,
   259  	)
   260  	tx.SetTransactionMeta(txMeta)
   261  
   262  	return tx, nil
   263  }
   264  
   265  // GetLatestEnqueue fetches the latest `enqueue`, meaning the `enqueue`
   266  // transaction with the greatest queue index.
   267  func (c *Client) GetLatestEnqueue() (*types.Transaction, error) {
   268  	response, err := c.client.R().
   269  		SetResult(&Enqueue{}).
   270  		Get("/enqueue/latest")
   271  
   272  	if err != nil {
   273  		return nil, fmt.Errorf("cannot fetch latest enqueue: %w", err)
   274  	}
   275  	enqueue, ok := response.Result().(*Enqueue)
   276  	if !ok {
   277  		return nil, errors.New("Cannot fetch latest enqueue")
   278  	}
   279  	tx, err := enqueueToTransaction(enqueue)
   280  	if err != nil {
   281  		return nil, fmt.Errorf("Cannot parse enqueue tx: %w", err)
   282  	}
   283  	return tx, nil
   284  }
   285  
   286  // GetLatestEnqueueIndex returns the latest `enqueue()` index
   287  func (c *Client) GetLatestEnqueueIndex() (*uint64, error) {
   288  	tx, err := c.GetLatestEnqueue()
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  	index := tx.GetMeta().QueueIndex
   293  	if index == nil {
   294  		return nil, errors.New("Latest queue index is nil")
   295  	}
   296  	return index, nil
   297  }
   298  
   299  // GetLatestTransactionIndex returns the latest CTC index that has been batch
   300  // submitted or not, depending on the backend
   301  func (c *Client) GetLatestTransactionIndex(backend Backend) (*uint64, error) {
   302  	tx, err := c.GetLatestTransaction(backend)
   303  	if err != nil {
   304  		return nil, err
   305  	}
   306  	index := tx.GetMeta().Index
   307  	if index == nil {
   308  		return nil, errors.New("Latest index is nil")
   309  	}
   310  	return index, nil
   311  }
   312  
   313  // GetLatestTransactionBatchIndex returns the latest transaction batch index
   314  func (c *Client) GetLatestTransactionBatchIndex() (*uint64, error) {
   315  	batch, _, err := c.GetLatestTransactionBatch()
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  	index := batch.Index
   320  	return &index, nil
   321  }
   322  
   323  // batchedTransactionToTransaction converts a transaction into a
   324  // types.Transaction that can be consumed by the SyncService
   325  func batchedTransactionToTransaction(res *transaction, chainID *big.Int) (*types.Transaction, error) {
   326  	// `nil` transactions are not found
   327  	if res == nil {
   328  		return nil, errElementNotFound
   329  	}
   330  	// The queue origin must be either sequencer of l1, otherwise
   331  	// it is considered an unknown queue origin and will not be processed
   332  	var queueOrigin types.QueueOrigin
   333  	switch res.QueueOrigin {
   334  	case sequencer:
   335  		queueOrigin = types.QueueOriginSequencer
   336  	case l1:
   337  		queueOrigin = types.QueueOriginL1ToL2
   338  	default:
   339  		return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin)
   340  	}
   341  	// Transactions that have been decoded are
   342  	// Queue Origin Sequencer transactions
   343  	if res.Decoded != nil {
   344  		nonce := res.Decoded.Nonce
   345  		to := res.Decoded.Target
   346  		value := (*big.Int)(res.Decoded.Value)
   347  		// Note: there are two gas limits, one top level and
   348  		// another on the raw transaction itself. Maybe maxGasLimit
   349  		// for the top level?
   350  		gasLimit := res.Decoded.GasLimit
   351  		gasPrice := new(big.Int).SetUint64(res.Decoded.GasPrice)
   352  		data := res.Decoded.Data
   353  
   354  		var tx *types.Transaction
   355  		if to == nil {
   356  			tx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, data)
   357  		} else {
   358  			tx = types.NewTransaction(nonce, *to, value, gasLimit, gasPrice, data)
   359  		}
   360  
   361  		txMeta := types.NewTransactionMeta(
   362  			new(big.Int).SetUint64(res.BlockNumber),
   363  			res.Timestamp,
   364  			res.Origin,
   365  			queueOrigin,
   366  			&res.Index,
   367  			res.QueueIndex,
   368  			res.Data,
   369  		)
   370  		tx.SetTransactionMeta(txMeta)
   371  
   372  		r, s := res.Decoded.Signature.R, res.Decoded.Signature.S
   373  		sig := make([]byte, crypto.SignatureLength)
   374  		copy(sig[32-len(r):32], r)
   375  		copy(sig[64-len(s):64], s)
   376  
   377  		var signer types.Signer
   378  		if res.Decoded.Signature.V == 27 || res.Decoded.Signature.V == 28 {
   379  			signer = types.HomesteadSigner{}
   380  			sig[64] = byte(res.Decoded.Signature.V - 27)
   381  		} else {
   382  			signer = types.NewEIP155Signer(chainID)
   383  			sig[64] = byte(res.Decoded.Signature.V)
   384  		}
   385  
   386  		tx, err := tx.WithSignature(signer, sig[:])
   387  		if err != nil {
   388  			return nil, fmt.Errorf("Cannot add signature to transaction: %w", err)
   389  		}
   390  
   391  		return tx, nil
   392  	}
   393  
   394  	// The transaction is  either an L1 to L2 transaction or it does not have a
   395  	// known deserialization
   396  	nonce := uint64(0)
   397  	if res.QueueOrigin == l1 {
   398  		if res.QueueIndex == nil {
   399  			return nil, errors.New("Queue origin L1 to L2 without a queue index")
   400  		}
   401  		nonce = *res.QueueIndex
   402  	}
   403  	target := res.Target
   404  	gasLimit := res.GasLimit
   405  	data := res.Data
   406  	origin := res.Origin
   407  	value := (*big.Int)(res.Value)
   408  	tx := types.NewTransaction(nonce, target, value, gasLimit, big.NewInt(0), data)
   409  	txMeta := types.NewTransactionMeta(
   410  		new(big.Int).SetUint64(res.BlockNumber),
   411  		res.Timestamp,
   412  		origin,
   413  		queueOrigin,
   414  		&res.Index,
   415  		res.QueueIndex,
   416  		res.Data,
   417  	)
   418  	tx.SetTransactionMeta(txMeta)
   419  	return tx, nil
   420  }
   421  
   422  // GetTransaction will get a transaction by Canonical Transaction Chain index
   423  func (c *Client) GetRawTransaction(index uint64, backend Backend) (*TransactionResponse, error) {
   424  	str := strconv.FormatUint(index, 10)
   425  	response, err := c.client.R().
   426  		SetPathParams(map[string]string{
   427  			"index": str,
   428  		}).
   429  		SetQueryParams(map[string]string{
   430  			"backend": backend.String(),
   431  		}).
   432  		SetResult(&TransactionResponse{}).
   433  		Get("/transaction/index/{index}")
   434  
   435  	if err != nil {
   436  		return nil, fmt.Errorf("cannot fetch transaction: %w", err)
   437  	}
   438  	res, ok := response.Result().(*TransactionResponse)
   439  	if !ok {
   440  		return nil, fmt.Errorf("could not get tx with index %d", index)
   441  	}
   442  	return res, nil
   443  }
   444  
   445  // GetTransaction will get a transaction by Canonical Transaction Chain index
   446  func (c *Client) GetTransaction(index uint64, backend Backend) (*types.Transaction, error) {
   447  	res, err := c.GetRawTransaction(index, backend)
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  	return batchedTransactionToTransaction(res.Transaction, c.chainID)
   452  }
   453  
   454  // GetLatestTransaction will get the latest transaction, meaning the transaction
   455  // with the greatest Canonical Transaction Chain index
   456  func (c *Client) GetLatestTransaction(backend Backend) (*types.Transaction, error) {
   457  	response, err := c.client.R().
   458  		SetResult(&TransactionResponse{}).
   459  		SetQueryParams(map[string]string{
   460  			"backend": backend.String(),
   461  		}).
   462  		Get("/transaction/latest")
   463  
   464  	if err != nil {
   465  		return nil, fmt.Errorf("cannot fetch latest transactions: %w", err)
   466  	}
   467  	res, ok := response.Result().(*TransactionResponse)
   468  	if !ok {
   469  		return nil, errors.New("Cannot get latest transaction")
   470  	}
   471  
   472  	return batchedTransactionToTransaction(res.Transaction, c.chainID)
   473  }
   474  
   475  // GetEthContext will return the EthContext by block number
   476  func (c *Client) GetEthContext(blockNumber uint64) (*EthContext, error) {
   477  	str := strconv.FormatUint(blockNumber, 10)
   478  	response, err := c.client.R().
   479  		SetPathParams(map[string]string{
   480  			"blocknumber": str,
   481  		}).
   482  		SetResult(&EthContext{}).
   483  		Get("/eth/context/blocknumber/{blocknumber}")
   484  
   485  	if err != nil {
   486  		return nil, err
   487  	}
   488  
   489  	context, ok := response.Result().(*EthContext)
   490  	if !ok {
   491  		return nil, errors.New("Cannot parse EthContext")
   492  	}
   493  	return context, nil
   494  }
   495  
   496  // GetLatestEthContext will return the latest EthContext
   497  func (c *Client) GetLatestEthContext() (*EthContext, error) {
   498  	response, err := c.client.R().
   499  		SetResult(&EthContext{}).
   500  		Get("/eth/context/latest")
   501  
   502  	if err != nil {
   503  		return nil, fmt.Errorf("Cannot fetch eth context: %w", err)
   504  	}
   505  
   506  	context, ok := response.Result().(*EthContext)
   507  	if !ok {
   508  		return nil, errors.New("Cannot parse EthContext")
   509  	}
   510  
   511  	return context, nil
   512  }
   513  
   514  // GetLastConfirmedEnqueue will get the last `enqueue` transaction that has been
   515  // batched up
   516  func (c *Client) GetLastConfirmedEnqueue() (*types.Transaction, error) {
   517  	enqueue, err := c.GetLatestEnqueue()
   518  	if err != nil {
   519  		return nil, fmt.Errorf("Cannot get latest enqueue: %w", err)
   520  	}
   521  	// This should only happen if there are no L1 to L2 transactions yet
   522  	if enqueue == nil {
   523  		return nil, errElementNotFound
   524  	}
   525  	// Work backwards looking for the first enqueue
   526  	// to have an index, which means it has been included
   527  	// in the canonical transaction chain.
   528  	for {
   529  		meta := enqueue.GetMeta()
   530  		// The enqueue has an index so it has been confirmed
   531  		if meta.Index != nil {
   532  			return enqueue, nil
   533  		}
   534  		// There is no queue index so this is a bug
   535  		if meta.QueueIndex == nil {
   536  			return nil, fmt.Errorf("queue index is nil")
   537  		}
   538  		// No enqueue transactions have been confirmed yet
   539  		if *meta.QueueIndex == uint64(0) {
   540  			return nil, errElementNotFound
   541  		}
   542  		next, err := c.GetEnqueue(*meta.QueueIndex - 1)
   543  		if err != nil {
   544  			return nil, fmt.Errorf("cannot get enqueue %d: %w", *meta.Index, err)
   545  		}
   546  		enqueue = next
   547  	}
   548  }
   549  
   550  // SyncStatus will query the remote server to determine if it is still syncing
   551  func (c *Client) SyncStatus(backend Backend) (*SyncStatus, error) {
   552  	response, err := c.client.R().
   553  		SetResult(&SyncStatus{}).
   554  		SetQueryParams(map[string]string{
   555  			"backend": backend.String(),
   556  		}).
   557  		Get("/eth/syncing")
   558  
   559  	if err != nil {
   560  		return nil, fmt.Errorf("Cannot fetch sync status: %w", err)
   561  	}
   562  
   563  	status, ok := response.Result().(*SyncStatus)
   564  	if !ok {
   565  		return nil, fmt.Errorf("Cannot parse sync status")
   566  	}
   567  
   568  	return status, nil
   569  }
   570  
   571  // GetLatestTransactionBatch will return the latest transaction batch
   572  func (c *Client) GetLatestTransactionBatch() (*Batch, []*types.Transaction, error) {
   573  	response, err := c.client.R().
   574  		SetResult(&TransactionBatchResponse{}).
   575  		Get("/batch/transaction/latest")
   576  
   577  	if err != nil {
   578  		return nil, nil, errors.New("Cannot get latest transaction batch")
   579  	}
   580  	txBatch, ok := response.Result().(*TransactionBatchResponse)
   581  	if !ok {
   582  		return nil, nil, fmt.Errorf("Cannot parse transaction batch response")
   583  	}
   584  	return parseTransactionBatchResponse(txBatch, c.chainID)
   585  }
   586  
   587  // GetTransactionBatch will return the transaction batch by batch index
   588  func (c *Client) GetTransactionBatch(index uint64) (*Batch, []*types.Transaction, error) {
   589  	str := strconv.FormatUint(index, 10)
   590  	response, err := c.client.R().
   591  		SetResult(&TransactionBatchResponse{}).
   592  		SetPathParams(map[string]string{
   593  			"index": str,
   594  		}).
   595  		Get("/batch/transaction/index/{index}")
   596  
   597  	if err != nil {
   598  		return nil, nil, fmt.Errorf("Cannot get transaction batch %d: %w", index, err)
   599  	}
   600  	txBatch, ok := response.Result().(*TransactionBatchResponse)
   601  	if !ok {
   602  		return nil, nil, fmt.Errorf("Cannot parse transaction batch response")
   603  	}
   604  	return parseTransactionBatchResponse(txBatch, c.chainID)
   605  }
   606  
   607  // parseTransactionBatchResponse will turn a TransactionBatchResponse into a
   608  // Batch and its corresponding types.Transactions
   609  func parseTransactionBatchResponse(txBatch *TransactionBatchResponse, chainID *big.Int) (*Batch, []*types.Transaction, error) {
   610  	if txBatch == nil || txBatch.Batch == nil {
   611  		return nil, nil, errElementNotFound
   612  	}
   613  	batch := txBatch.Batch
   614  	txs := make([]*types.Transaction, len(txBatch.Transactions))
   615  	for i, tx := range txBatch.Transactions {
   616  		transaction, err := batchedTransactionToTransaction(tx, chainID)
   617  		if err != nil {
   618  			return nil, nil, fmt.Errorf("Cannot parse transaction batch: %w", err)
   619  		}
   620  		txs[i] = transaction
   621  	}
   622  	return batch, txs, nil
   623  }