func (v *batchVerifier) Verify(batch *Batch) error {
	if batch.Version != CurrentBatchVersion {
		return ErrVersionMismatch
	}
	tallies := make(map[[33]byte]*AccountTally)
	accounts := make(map[[33]byte]*account.Account)
	for nonce, theirOrders := range batch.MatchedOrders {
		ourOrder, err := v.orderStore.GetOrder(nonce)
		if err != nil {
			return fmt.Errorf("order %v not found: %v", nonce, err)
		}
		acctKeyRaw := ourOrder.Details().AcctKey
		acctKey, err := btcec.ParsePubKey(acctKeyRaw[:], btcec.S256())
		if err != nil {
			return err
		}
		tally, ok := tallies[acctKeyRaw]
		if !ok {
			acct, err := v.getAccount(acctKey)
			if err != nil {
				return fmt.Errorf("account %x not found: %v",
					acctKeyRaw, err)
			}
			tally = &AccountTally{
				EndingBalance: acct.Value,
			}
			tallies[acctKeyRaw] = tally
			accounts[acctKeyRaw] = acct
		}
		ourOrderDuration := ourOrder.Details().LeaseDuration
		clearingPrice := batch.ClearingPrices[ourOrderDuration]
		unitsFilled := SupplyUnit(0)
		for _, theirOrder := range theirOrders {
			err = v.validateMatchedOrder(
				tally, ourOrder, theirOrder, batch.ExecutionFee,
				clearingPrice,
			)
			if err != nil {
				return newMismatchErr(
					err, "error matching against order %v",
					theirOrder.Order.Nonce(),
				)
			}
			err = v.validateChannelOutput(
				batch, ourOrder, theirOrder,
			)
			if err != nil {
				return newMismatchErr(
					err, "error finding channel output "+
						"for matched order %v",
					theirOrder.Order.Nonce(),
				)
			}
			tally.NumChansCreated++
			unitsFilled += theirOrder.UnitsFilled
		}
		ourOrderPrice := FixedRatePremium(ourOrder.Details().FixedRate)
		switch {
		case ourOrder.Type() == TypeBid && ourOrderPrice < clearingPrice:
			return &MismatchErr{
				msg: fmt.Sprintf("bid order %v has price %v "+
					"below clearing price %v", nonce,
					ourOrderPrice, clearingPrice),
			}
		case ourOrder.Type() == TypeAsk && ourOrderPrice > clearingPrice:
			return &MismatchErr{
				msg: fmt.Sprintf("ask order %v has price %v "+
					"above clearing price %v", nonce,
					ourOrderPrice, clearingPrice),
			}
		}
		switch {
		case unitsFilled > ourOrder.Details().UnitsUnfulfilled:
			return &MismatchErr{
				msg: fmt.Sprintf("invalid units to be filled "+
					"for order %v. currently unfulfilled "+
					"%d, matched with %d in total",
					ourOrder.Nonce(),
					ourOrder.Details().UnitsUnfulfilled,
					unitsFilled,
				),
			}
		case unitsFilled < ourOrder.Details().MinUnitsMatch:
			return &MismatchErr{
				msg: fmt.Sprintf("invalid units to be filled "+
					"for order %v. matched %d units, but "+
					"minimum is %d", ourOrder.Nonce(),
					unitsFilled,
					ourOrder.Details().MinUnitsMatch),
			}
		}
	}
	for _, diff := range batch.AccountDiffs {
		tally, ok := tallies[diff.AccountKeyRaw]
		if !ok {
			return &MismatchErr{
				msg: fmt.Sprintf("got diff for uninvolved "+
					"account %x", diff.AccountKeyRaw),
			}
		}
		acct := accounts[diff.AccountKeyRaw]
		tally.ChainFees(batch.BatchTxFeeRate)
		if diff.EndingBalance != tally.EndingBalance {
			return &MismatchErr{
				msg: fmt.Sprintf("server sent unexpected "+
					"ending balance. got %d expected %d",
					diff.EndingBalance, tally.EndingBalance),
			}
		}
		err := diff.validateEndingState(batch.BatchTX, acct)
		if err != nil {
			return newMismatchErr(
				err, "account %x diff is incorrect",
				diff.AccountKeyRaw,
			)
		}
	}
	return nil
}
Verify makes sure the batch prepared by the server is correct and can be
accepted by the trader.

NOTE: This method is part of the BatchVerifier interface.
package order
import (
	"errors"
	"fmt"
	"time"
	"github.com/btcsuite/btcd/btcec"
	"github.com/lightninglabs/lndclient"
	"github.com/lightninglabs/pool/account"
	"github.com/lightninglabs/pool/terms"
)
const (
	deriveKeyTimeout = 10 * time.Second
)
var (
	ErrMismatchErr = errors.New("batch verification result mismatch")
)
type MismatchErr struct {
	msg   string
	cause error
}
func (m *MismatchErr) Unwrap() error {
	return ErrMismatchErr
}
func (m *MismatchErr) Error() string {
	if m.cause == nil {
		return m.msg
	}
	return fmt.Sprintf("%s: %v", m.msg, m.cause)
}
func newMismatchErr(cause error, msg string, args ...interface{}) error {
	return &MismatchErr{
		msg:   fmt.Sprintf(msg, args...),
		cause: cause,
	}
}
type batchVerifier struct {
	orderStore    Store
	getAccount    func(*btcec.PublicKey) (*account.Account, error)
	wallet        lndclient.WalletKitClient
	ourNodePubkey [33]byte
}