You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: dealstatematcher.go
    path of file: ./repos/lotus/markets/storageadapter
    
    the code of the file until where you have to start completion: package storageadapter

import (
	"context"
	"sync"

	"github.com/filecoin-project/go-state-types/abi"

	actorsmarket "github.com/filecoin-project/lotus/chain/actors/builtin/market"
	"github.com/filecoin-project/lotus/chain/events"
	"github.com/filecoin-project/lotus/chain/event
    
func (mc *dealStateMatcher) matcher(ctx context.Context, dealID abi.DealID) events.StateMatchFunc {
	// The function that is called to check if the deal state has changed for
	// the target deal ID
	dealStateChangedForID := mc.preds.DealStateChangedForIDs([]abi.DealID{dealID})

	// The match function is called by the events API to check if there's
	// been a state change for the deal with the target deal ID
	match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
		mc.lk.Lock()
		defer mc.lk.Unlock()

		// Check if we've already fetched the DealStates for the given tipsets
		if mc.oldTsk == oldTs.Key() && mc.newTsk == newTs.Key() {
			// If we fetch the DealStates and there is no difference between
			// them, they are stored as nil. So we can just bail out.
			if mc.oldDealStateRoot == nil || mc.newDealStateRoot == nil {
				return false, nil, nil
			}

			// Check if the deal state has changed for the target ID
			return dealStateChangedForID(ctx, mc.oldDealStateRoot, mc.newDealStateRoot)
		}

		// We haven't already fetched the DealStates for the given tipsets, so
		// do so now

		// Replace dealStateChangedForID with a function that records the
		// DealStates so that we can cache them
		var oldDealStateRootSaved, newDealStateRootSaved actorsmarket.DealStates
		recorder := func(ctx context.Context, oldDealStateRoot, newDealStateRoot actorsmarket.DealStates) (changed bool, user state.UserData, err error) {
			// Record DealStates
			oldDealStateRootSaved = oldDealStateRoot
			newDealStateRootSaved = newDealStateRoot

			return dealStateChangedForID(ctx, oldDealStateRoot, newDealStateRoot)
		}

		// Call the match function
		dealDiff := mc.preds.OnStorageMarketActorChanged(
			mc.preds.OnDealStateChanged(recorder))
		matched, data, err := dealDiff(ctx, oldTs.Key(), newTs.Key())

		// Save the recorded DealStates for the tipsets
		mc.oldTsk = oldTs.Key()
		mc.newTsk = newTs.Key()
		mc.oldDealStateRoot = oldDealStateRootSaved
		mc.newDealStateRoot = newDealStateRootSaved

		return matched, data, err
	}
	return match
}