diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go
index 2305063fc..78c955e72 100644
--- a/pkg/innerring/innerring.go
+++ b/pkg/innerring/innerring.go
@@ -67,6 +67,8 @@ type (
 		precision     precision.Fixed8Converter
 		auditClient   *auditWrapper.ClientWrapper
 		healthStatus  atomic.Value
+		balanceClient *balanceWrapper.Wrapper
+		netmapClient  *nmWrapper.Wrapper
 
 		// notary configuration
 		feeConfig        *config.FeeConfig
@@ -139,10 +141,6 @@ const (
 	notaryExtraBlocks = 300
 	// amount of tries before notary deposit timeout.
 	notaryDepositTimeout = 100
-
-	precisionMethod = "decimals"
-	// netmap
-	getEpochMethod = "epoch"
 )
 
 var (
@@ -404,12 +402,12 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		return nil, err
 	}
 
-	nmClient, err := nmWrapper.NewFromMorph(server.morphClient, server.contracts.netmap, fee)
+	server.netmapClient, err = nmWrapper.NewFromMorph(server.morphClient, server.contracts.netmap, fee)
 	if err != nil {
 		return nil, err
 	}
 
-	balClient, err := balanceWrapper.NewFromMorph(server.morphClient, server.contracts.balance, fee, balanceWrapper.TryNotary())
+	server.balanceClient, err = balanceWrapper.NewFromMorph(server.morphClient, server.contracts.balance, fee, balanceWrapper.TryNotary())
 	if err != nil {
 		return nil, err
 	}
@@ -425,7 +423,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 	}
 
 	// create global runtime config reader
-	globalConfig := config.NewGlobalConfigReader(cfg, nmClient)
+	globalConfig := config.NewGlobalConfigReader(cfg, server.netmapClient)
 
 	clientCache := newClientCache(&clientCacheParams{
 		Log:          log,
@@ -459,18 +457,18 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 
 	// create audit processor
 	auditProcessor, err := audit.New(&audit.Params{
-		Log:               log,
-		NetmapContract:    server.contracts.netmap,
-		ContainerContract: server.contracts.container,
-		AuditContract:     server.contracts.audit,
-		MorphClient:       server.morphClient,
-		IRList:            server,
-		FeeProvider:       server.feeConfig,
-		ClientCache:       clientCache,
-		Key:               &server.key.PrivateKey,
-		RPCSearchTimeout:  cfg.GetDuration("audit.timeout.search"),
-		TaskManager:       auditTaskManager,
-		Reporter:          server,
+		Log:              log,
+		NetmapClient:     server.netmapClient,
+		ContainerClient:  cnrClient,
+		AuditContract:    server.contracts.audit,
+		MorphClient:      server.morphClient,
+		IRList:           server,
+		FeeProvider:      server.feeConfig,
+		ClientCache:      clientCache,
+		Key:              &server.key.PrivateKey,
+		RPCSearchTimeout: cfg.GetDuration("audit.timeout.search"),
+		TaskManager:      auditTaskManager,
+		Reporter:         server,
 	})
 	if err != nil {
 		return nil, err
@@ -482,9 +480,9 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		log:           server.log,
 		cnrSrc:        cntWrapper.AsContainerSource(cnrClient),
 		auditClient:   server.auditClient,
-		nmSrc:         nmClient,
+		nmSrc:         server.netmapClient,
 		clientCache:   clientCache,
-		balanceClient: balClient,
+		balanceClient: server.balanceClient,
 	}
 
 	auditCalcDeps := &auditSettlementDeps{
@@ -528,7 +526,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 	governanceProcessor, err := governance.New(&governance.Params{
 		Log:            log,
 		NeoFSContract:  server.contracts.neofs,
-		NetmapContract: server.contracts.netmap,
+		NetmapClient:   server.netmapClient,
 		AlphabetState:  server,
 		EpochState:     server,
 		Voter:          server,
@@ -560,8 +558,8 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		Log:              log,
 		PoolSize:         cfg.GetInt("workers.netmap"),
 		NetmapContract:   server.contracts.netmap,
+		NetmapClient:     server.netmapClient,
 		EpochTimer:       server,
-		MorphClient:      server.morphClient,
 		EpochState:       server,
 		AlphabetState:    server,
 		CleanupEnabled:   cfg.GetBool("netmap_cleaner.enabled"),
@@ -596,7 +594,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		FeeProvider:       server.feeConfig,
 		ContainerClient:   cnrClient,
 		NeoFSIDClient:     neofsIDClient,
-		NetworkState:      nmClient,
+		NetworkState:      server.netmapClient,
 	})
 	if err != nil {
 		return nil, err
@@ -632,9 +630,9 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		Log:                 log,
 		PoolSize:            cfg.GetInt("workers.neofs"),
 		NeoFSContract:       server.contracts.neofs,
-		BalanceContract:     server.contracts.balance,
-		NetmapContract:      server.contracts.netmap,
-		NeoFSIDContract:     server.contracts.neofsID,
+		NeoFSIDClient:       neofsIDClient,
+		BalanceClient:       server.balanceClient,
+		NetmapClient:        server.netmapClient,
 		MorphClient:         server.morphClient,
 		EpochState:          server,
 		AlphabetState:       server,
@@ -659,7 +657,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		Log:               log,
 		PoolSize:          cfg.GetInt("workers.alphabet"),
 		AlphabetContracts: server.contracts.alphabet,
-		NetmapContract:    server.contracts.netmap,
+		NetmapClient:      server.netmapClient,
 		MorphClient:       server.morphClient,
 		IRList:            server,
 		StorageEmission:   cfg.GetUint64("emit.storage.amount"),
@@ -683,7 +681,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		ReputationWrapper:  repClient,
 		ManagerBuilder: reputationcommon.NewManagerBuilder(
 			reputationcommon.ManagersPrm{
-				NetMapSource: nmClient,
+				NetMapSource: server.netmapClient,
 			},
 		),
 	})
@@ -946,35 +944,25 @@ func parseAlphabetContracts(cfg *viper.Viper) (alphabetContracts, error) {
 
 func (s *Server) initConfigFromBlockchain() error {
 	// get current epoch
-	val, err := s.morphClient.TestInvoke(s.contracts.netmap, getEpochMethod)
-	if err != nil {
-		return fmt.Errorf("can't read epoch: %w", err)
-	}
-
-	epoch, err := client.IntFromStackItem(val[0])
+	epoch, err := s.netmapClient.Epoch()
 	if err != nil {
 		return fmt.Errorf("can't parse epoch: %w", err)
 	}
 
 	// get balance precision
-	v, err := s.morphClient.TestInvoke(s.contracts.balance, precisionMethod)
+	balancePrecision, err := s.balanceClient.Decimals()
 	if err != nil {
 		return fmt.Errorf("can't read balance contract precision: %w", err)
 	}
 
-	balancePrecision, err := client.IntFromStackItem(v[0])
-	if err != nil {
-		return fmt.Errorf("can't parse balance contract precision: %w", err)
-	}
-
-	s.epochCounter.Store(uint64(epoch))
-	s.precision.SetBalancePrecision(uint32(balancePrecision))
+	s.epochCounter.Store(epoch)
+	s.precision.SetBalancePrecision(balancePrecision)
 
 	s.log.Debug("read config from blockchain",
 		zap.Bool("active", s.IsActive()),
 		zap.Bool("alphabet", s.IsAlphabet()),
-		zap.Int64("epoch", epoch),
-		zap.Uint32("precision", uint32(balancePrecision)),
+		zap.Uint64("epoch", epoch),
+		zap.Uint32("precision", balancePrecision),
 	)
 
 	return nil
diff --git a/pkg/innerring/processors/alphabet/process_emit.go b/pkg/innerring/processors/alphabet/process_emit.go
index 742d97d7f..fa880e6af 100644
--- a/pkg/innerring/processors/alphabet/process_emit.go
+++ b/pkg/innerring/processors/alphabet/process_emit.go
@@ -5,7 +5,6 @@ import (
 
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
-	"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/snapshot"
 	"go.uber.org/zap"
 )
 
@@ -41,7 +40,7 @@ func (np *Processor) processEmit() {
 		return
 	}
 
-	networkMap, err := snapshot.Fetch(np.morphClient, np.netmapContract)
+	networkMap, err := np.netmapClient.Snapshot()
 	if err != nil {
 		np.log.Warn("can't get netmap snapshot to emit gas to storage nodes",
 			zap.String("error", err.Error()))
diff --git a/pkg/innerring/processors/alphabet/processor.go b/pkg/innerring/processors/alphabet/processor.go
index d41d1a51d..54efc0980 100644
--- a/pkg/innerring/processors/alphabet/processor.go
+++ b/pkg/innerring/processors/alphabet/processor.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
+	nmWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
 	"github.com/panjf2000/ants/v2"
 	"go.uber.org/zap"
@@ -34,7 +35,7 @@ type (
 		log               *zap.Logger
 		pool              *ants.Pool
 		alphabetContracts Contracts
-		netmapContract    util.Uint160
+		netmapClient      *nmWrapper.Wrapper
 		morphClient       *client.Client
 		irList            Indexer
 		storageEmission   uint64
@@ -45,7 +46,7 @@ type (
 		Log               *zap.Logger
 		PoolSize          int
 		AlphabetContracts Contracts
-		NetmapContract    util.Uint160
+		NetmapClient      *nmWrapper.Wrapper
 		MorphClient       *client.Client
 		IRList            Indexer
 		StorageEmission   uint64
@@ -74,7 +75,7 @@ func New(p *Params) (*Processor, error) {
 		log:               p.Log,
 		pool:              pool,
 		alphabetContracts: p.AlphabetContracts,
-		netmapContract:    p.NetmapContract,
+		netmapClient:      p.NetmapClient,
 		morphClient:       p.MorphClient,
 		irList:            p.IRList,
 		storageEmission:   p.StorageEmission,
diff --git a/pkg/innerring/processors/audit/processor.go b/pkg/innerring/processors/audit/processor.go
index 23ef5259d..04ff912d4 100644
--- a/pkg/innerring/processors/audit/processor.go
+++ b/pkg/innerring/processors/audit/processor.go
@@ -42,15 +42,14 @@ type (
 
 	// Processor of events related with data audit.
 	Processor struct {
-		log               *zap.Logger
-		pool              *ants.Pool
-		containerContract util.Uint160
-		auditContract     util.Uint160
-		morphClient       *client.Client
-		irList            Indexer
-		clientCache       NeoFSClientCache
-		key               *ecdsa.PrivateKey
-		searchTimeout     time.Duration
+		log           *zap.Logger
+		pool          *ants.Pool
+		auditContract util.Uint160
+		morphClient   *client.Client
+		irList        Indexer
+		clientCache   NeoFSClientCache
+		key           *ecdsa.PrivateKey
+		searchTimeout time.Duration
 
 		containerClient *wrapContainer.Wrapper
 		netmapClient    *wrapNetmap.Wrapper
@@ -62,18 +61,18 @@ type (
 
 	// Params of the processor constructor.
 	Params struct {
-		Log               *zap.Logger
-		NetmapContract    util.Uint160
-		ContainerContract util.Uint160
-		AuditContract     util.Uint160
-		MorphClient       *client.Client
-		IRList            Indexer
-		FeeProvider       *config.FeeConfig
-		ClientCache       NeoFSClientCache
-		RPCSearchTimeout  time.Duration
-		TaskManager       TaskManager
-		Reporter          audit.Reporter
-		Key               *ecdsa.PrivateKey
+		Log              *zap.Logger
+		NetmapClient     *wrapNetmap.Wrapper
+		ContainerClient  *wrapContainer.Wrapper
+		AuditContract    util.Uint160
+		MorphClient      *client.Client
+		IRList           Indexer
+		FeeProvider      *config.FeeConfig
+		ClientCache      NeoFSClientCache
+		RPCSearchTimeout time.Duration
+		TaskManager      TaskManager
+		Reporter         audit.Reporter
+		Key              *ecdsa.PrivateKey
 	}
 )
 
@@ -114,30 +113,17 @@ func New(p *Params) (*Processor, error) {
 		return nil, fmt.Errorf("ir/audit: can't create worker pool: %w", err)
 	}
 
-	// creating enhanced client for getting network map
-	netmapClient, err := wrapNetmap.NewFromMorph(p.MorphClient, p.NetmapContract, p.FeeProvider.SideChainFee())
-	if err != nil {
-		return nil, err
-	}
-
-	// creating enhanced client for getting containers
-	containerClient, err := wrapContainer.NewFromMorph(p.MorphClient, p.ContainerContract, p.FeeProvider.SideChainFee())
-	if err != nil {
-		return nil, err
-	}
-
 	return &Processor{
 		log:               p.Log,
 		pool:              pool,
-		containerContract: p.ContainerContract,
+		containerClient:   p.ContainerClient,
 		auditContract:     p.AuditContract,
 		morphClient:       p.MorphClient,
 		irList:            p.IRList,
 		clientCache:       p.ClientCache,
 		key:               p.Key,
 		searchTimeout:     p.RPCSearchTimeout,
-		containerClient:   containerClient,
-		netmapClient:      netmapClient,
+		netmapClient:      p.NetmapClient,
 		taskManager:       p.TaskManager,
 		reporter:          p.Reporter,
 		prevAuditCanceler: func() {},
diff --git a/pkg/innerring/processors/governance/process_update.go b/pkg/innerring/processors/governance/process_update.go
index 7b45cf589..11cfa344f 100644
--- a/pkg/innerring/processors/governance/process_update.go
+++ b/pkg/innerring/processors/governance/process_update.go
@@ -11,7 +11,6 @@ const (
 	alphabetUpdateIDPrefix = "AlphabetUpdate"
 
 	alphabetUpdateMethod = "alphabetUpdate"
-	setInnerRingMethod   = "updateInnerRing"
 )
 
 func (gp *Processor) processAlphabetSync() {
@@ -70,8 +69,7 @@ func (gp *Processor) processAlphabetSync() {
 			sort.Sort(newInnerRing)
 
 			if gp.notaryDisabled {
-				err = gp.morphClient.NotaryInvoke(gp.netmapContract, gp.feeProvider.SideChainFee(), setInnerRingMethod,
-					newInnerRing)
+				err = gp.netmapClient.SetInnerRing(newInnerRing)
 			} else {
 				err = gp.morphClient.UpdateNeoFSAlphabetList(newInnerRing)
 			}
diff --git a/pkg/innerring/processors/governance/processor.go b/pkg/innerring/processors/governance/processor.go
index e663469ff..d8fa00d47 100644
--- a/pkg/innerring/processors/governance/processor.go
+++ b/pkg/innerring/processors/governance/processor.go
@@ -9,6 +9,7 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/config"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
+	nmWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event/rolemanagement"
 	"github.com/panjf2000/ants/v2"
@@ -38,10 +39,10 @@ type (
 
 	// Processor of events related to governance in the network.
 	Processor struct {
-		log            *zap.Logger
-		pool           *ants.Pool
-		neofsContract  util.Uint160
-		netmapContract util.Uint160
+		log           *zap.Logger
+		pool          *ants.Pool
+		neofsContract util.Uint160
+		netmapClient  *nmWrapper.Wrapper
 
 		alphabetState AlphabetState
 		epochState    EpochState
@@ -56,9 +57,8 @@ type (
 
 	// Params of the processor constructor.
 	Params struct {
-		Log            *zap.Logger
-		NeoFSContract  util.Uint160
-		NetmapContract util.Uint160
+		Log           *zap.Logger
+		NeoFSContract util.Uint160
 
 		AlphabetState AlphabetState
 		EpochState    EpochState
@@ -66,6 +66,7 @@ type (
 
 		MorphClient   *client.Client
 		MainnetClient *client.Client
+		NetmapClient  *nmWrapper.Wrapper
 
 		NotaryDisabled bool
 		FeeProvider    *config.FeeConfig
@@ -100,7 +101,7 @@ func New(p *Params) (*Processor, error) {
 		log:            p.Log,
 		pool:           pool,
 		neofsContract:  p.NeoFSContract,
-		netmapContract: p.NetmapContract,
+		netmapClient:   p.NetmapClient,
 		alphabetState:  p.AlphabetState,
 		epochState:     p.EpochState,
 		voter:          p.Voter,
diff --git a/pkg/innerring/processors/neofs/process_assets.go b/pkg/innerring/processors/neofs/process_assets.go
index daeda154a..987d748e7 100644
--- a/pkg/innerring/processors/neofs/process_assets.go
+++ b/pkg/innerring/processors/neofs/process_assets.go
@@ -9,10 +9,6 @@ import (
 const (
 	// lockAccountLifeTime defines amount of epochs when lock account is valid.
 	lockAccountLifetime uint64 = 20
-
-	burnMethod = "burn"
-	lockMethod = "lock"
-	mintMethod = "mint"
 )
 
 // Process deposit event by invoking balance contract and sending native
@@ -24,8 +20,8 @@ func (np *Processor) processDeposit(deposit *neofsEvent.Deposit) {
 	}
 
 	// send transferX to balance contract
-	err := np.morphClient.NotaryInvoke(np.balanceContract, np.feeProvider.SideChainFee(), mintMethod,
-		deposit.To().BytesBE(),
+	err := np.balanceClient.Mint(
+		deposit.To(),
 		np.converter.ToBalancePrecision(deposit.Amount()),
 		deposit.ID())
 	if err != nil {
@@ -95,7 +91,7 @@ func (np *Processor) processWithdraw(withdraw *neofsEvent.Withdraw) {
 
 	curEpoch := np.epochState.EpochCounter()
 
-	err = np.morphClient.NotaryInvoke(np.balanceContract, np.feeProvider.SideChainFee(), lockMethod,
+	err = np.balanceClient.Lock(
 		withdraw.ID(),
 		withdraw.User(),
 		lock,
@@ -114,8 +110,8 @@ func (np *Processor) processCheque(cheque *neofsEvent.Cheque) {
 		return
 	}
 
-	err := np.morphClient.NotaryInvoke(np.balanceContract, np.feeProvider.SideChainFee(), burnMethod,
-		cheque.LockAccount().BytesBE(),
+	err := np.balanceClient.Burn(
+		cheque.LockAccount(),
 		np.converter.ToBalancePrecision(cheque.Amount()),
 		cheque.ID())
 	if err != nil {
diff --git a/pkg/innerring/processors/neofs/process_config.go b/pkg/innerring/processors/neofs/process_config.go
index 283260b7d..3a494640d 100644
--- a/pkg/innerring/processors/neofs/process_config.go
+++ b/pkg/innerring/processors/neofs/process_config.go
@@ -5,8 +5,6 @@ import (
 	"go.uber.org/zap"
 )
 
-const setConfigMethod = "setConfig"
-
 // Process config event by setting configuration value from main chain in
 // side chain.
 func (np *Processor) processConfig(config *neofsEvent.Config) {
@@ -15,8 +13,7 @@ func (np *Processor) processConfig(config *neofsEvent.Config) {
 		return
 	}
 
-	err := np.morphClient.NotaryInvoke(np.netmapContract, np.feeProvider.SideChainFee(), setConfigMethod,
-		config.ID(), config.Key(), config.Value())
+	err := np.netmapClient.SetConfig(config.ID(), config.Key(), config.Value())
 	if err != nil {
 		np.log.Error("can't relay set config event", zap.Error(err))
 	}
diff --git a/pkg/innerring/processors/neofs/processor.go b/pkg/innerring/processors/neofs/processor.go
index 814cc19a0..47aa84bf3 100644
--- a/pkg/innerring/processors/neofs/processor.go
+++ b/pkg/innerring/processors/neofs/processor.go
@@ -10,7 +10,9 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/config"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
+	balanceWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper"
 	neofsid "github.com/nspcc-dev/neofs-node/pkg/morph/client/neofsid/wrapper"
+	nmWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
 	neofsEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/neofs"
 	"github.com/panjf2000/ants/v2"
@@ -38,9 +40,9 @@ type (
 		log                 *zap.Logger
 		pool                *ants.Pool
 		neofsContract       util.Uint160
-		balanceContract     util.Uint160
-		netmapContract      util.Uint160
 		neofsIDContract     util.Uint160
+		balanceClient       *balanceWrapper.Wrapper
+		netmapClient        *nmWrapper.Wrapper
 		morphClient         *client.Client
 		epochState          EpochState
 		alphabetState       AlphabetState
@@ -60,9 +62,9 @@ type (
 		Log                 *zap.Logger
 		PoolSize            int
 		NeoFSContract       util.Uint160
-		BalanceContract     util.Uint160
-		NetmapContract      util.Uint160
-		NeoFSIDContract     util.Uint160
+		NeoFSIDClient       *neofsid.ClientWrapper
+		BalanceClient       *balanceWrapper.Wrapper
+		NetmapClient        *nmWrapper.Wrapper
 		MorphClient         *client.Client
 		EpochState          EpochState
 		AlphabetState       AlphabetState
@@ -113,17 +115,12 @@ func New(p *Params) (*Processor, error) {
 		return nil, fmt.Errorf("ir/neofs: can't create LRU cache for gas emission: %w", err)
 	}
 
-	clientWrapper, err := neofsid.NewFromMorph(p.MorphClient, p.NeoFSIDContract, p.FeeProvider.SideChainFee())
-	if err != nil {
-		return nil, fmt.Errorf("could not create NeoFS ID client wrapper: %w", err)
-	}
-
 	return &Processor{
 		log:                 p.Log,
 		pool:                pool,
 		neofsContract:       p.NeoFSContract,
-		balanceContract:     p.BalanceContract,
-		netmapContract:      p.NetmapContract,
+		balanceClient:       p.BalanceClient,
+		netmapClient:        p.NetmapClient,
 		morphClient:         p.MorphClient,
 		epochState:          p.EpochState,
 		alphabetState:       p.AlphabetState,
@@ -135,7 +132,7 @@ func New(p *Params) (*Processor, error) {
 		mintEmitValue:       p.MintEmitValue,
 		gasBalanceThreshold: p.GasBalanceThreshold,
 
-		neofsIDClient: clientWrapper,
+		neofsIDClient: p.NeoFSIDClient,
 	}, nil
 }
 
diff --git a/pkg/innerring/processors/netmap/process_cleanup.go b/pkg/innerring/processors/netmap/process_cleanup.go
index ab51cb327..04cd15913 100644
--- a/pkg/innerring/processors/netmap/process_cleanup.go
+++ b/pkg/innerring/processors/netmap/process_cleanup.go
@@ -6,8 +6,6 @@ import (
 	"go.uber.org/zap"
 )
 
-const updatePeerStateMethod = "updateState"
-
 func (np *Processor) processNetmapCleanupTick(epoch uint64) {
 	if !np.alphabetState.IsAlphabet() {
 		np.log.Info("non alphabet mode, ignore new netmap cleanup tick")
@@ -26,9 +24,7 @@ func (np *Processor) processNetmapCleanupTick(epoch uint64) {
 
 		np.log.Info("vote to remove node from netmap", zap.String("key", s))
 
-		err = np.morphClient.NotaryInvoke(np.netmapContract, np.feeProvider.SideChainFee(), updatePeerStateMethod,
-			int64(netmap.NodeStateOffline.ToV2()),
-			key.Bytes())
+		err = np.netmapClient.UpdatePeerState(key.Bytes(), netmap.NodeStateOffline)
 		if err != nil {
 			np.log.Error("can't invoke netmap.UpdateState", zap.Error(err))
 		}
diff --git a/pkg/innerring/processors/netmap/process_epoch.go b/pkg/innerring/processors/netmap/process_epoch.go
index 87fcc1226..1a94542f5 100644
--- a/pkg/innerring/processors/netmap/process_epoch.go
+++ b/pkg/innerring/processors/netmap/process_epoch.go
@@ -3,13 +3,10 @@ package netmap
 import (
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/governance"
-	"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/snapshot"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement"
 	"go.uber.org/zap"
 )
 
-const setNewEpochMethod = "newEpoch"
-
 // Process new epoch notification by setting global epoch value and resetting
 // local epoch timer.
 func (np *Processor) processNewEpoch(epoch uint64) {
@@ -20,7 +17,7 @@ func (np *Processor) processNewEpoch(epoch uint64) {
 	}
 
 	// get new netmap snapshot
-	networkMap, err := snapshot.Fetch(np.morphClient, np.netmapContract)
+	networkMap, err := np.netmapClient.Snapshot()
 	if err != nil {
 		np.log.Warn("can't get netmap snapshot to perform cleanup",
 			zap.String("error", err.Error()))
@@ -55,7 +52,7 @@ func (np *Processor) processNewEpochTick() {
 	nextEpoch := np.epochState.EpochCounter() + 1
 	np.log.Debug("next epoch", zap.Uint64("value", nextEpoch))
 
-	err := np.morphClient.NotaryInvoke(np.netmapContract, np.feeProvider.SideChainFee(), setNewEpochMethod, int64(nextEpoch))
+	err := np.netmapClient.NewEpoch(nextEpoch)
 	if err != nil {
 		np.log.Error("can't invoke netmap.NewEpoch", zap.Error(err))
 	}
diff --git a/pkg/innerring/processors/netmap/process_peers.go b/pkg/innerring/processors/netmap/process_peers.go
index 4f91b59a8..96f3c1e1f 100644
--- a/pkg/innerring/processors/netmap/process_peers.go
+++ b/pkg/innerring/processors/netmap/process_peers.go
@@ -10,8 +10,6 @@ import (
 	"go.uber.org/zap"
 )
 
-const approvePeerMethod = "addPeer"
-
 // Process add peer notification by sanity check of new node
 // local epoch timer.
 func (np *Processor) processAddPeer(node []byte) {
@@ -52,14 +50,6 @@ func (np *Processor) processAddPeer(node []byte) {
 	})
 	nodeInfo.SetAttributes(a...)
 
-	// marshal node info back to binary
-	node, err = nodeInfo.Marshal()
-	if err != nil {
-		np.log.Warn("can't marshal approved network map candidate",
-			zap.String("error", err.Error()))
-		return
-	}
-
 	keyString := hex.EncodeToString(nodeInfo.PublicKey())
 
 	exists := np.netmapSnapshot.touch(keyString, np.epochState.EpochCounter())
@@ -67,7 +57,7 @@ func (np *Processor) processAddPeer(node []byte) {
 		np.log.Info("approving network map candidate",
 			zap.String("key", keyString))
 
-		err := np.morphClient.NotaryInvoke(np.netmapContract, np.feeProvider.SideChainFee(), approvePeerMethod, node)
+		err := np.netmapClient.AddPeer(nodeInfo)
 		if err != nil {
 			np.log.Error("can't invoke netmap.AddPeer", zap.Error(err))
 		}
@@ -94,9 +84,7 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
 	// again before new epoch will tick
 	np.netmapSnapshot.flag(hex.EncodeToString(ev.PublicKey().Bytes()))
 
-	err := np.morphClient.NotaryInvoke(np.netmapContract, np.feeProvider.SideChainFee(), updatePeerStateMethod,
-		int64(ev.Status().ToV2()),
-		ev.PublicKey().Bytes())
+	err := np.netmapClient.UpdatePeerState(ev.PublicKey().Bytes(), ev.Status())
 	if err != nil {
 		np.log.Error("can't invoke netmap.UpdatePeer", zap.Error(err))
 	}
diff --git a/pkg/innerring/processors/netmap/processor.go b/pkg/innerring/processors/netmap/processor.go
index 9633602c7..9e865d332 100644
--- a/pkg/innerring/processors/netmap/processor.go
+++ b/pkg/innerring/processors/netmap/processor.go
@@ -7,8 +7,8 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/config"
-	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
 	container "github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper"
+	nmWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
 	netmapEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
 	"github.com/panjf2000/ants/v2"
@@ -57,7 +57,7 @@ type (
 		epochState     EpochState
 		alphabetState  AlphabetState
 
-		morphClient  *client.Client
+		netmapClient *nmWrapper.Wrapper
 		containerWrp *container.Wrapper
 
 		netmapSnapshot cleanupTable
@@ -73,11 +73,12 @@ type (
 
 	// Params of the processor constructor.
 	Params struct {
-		Log              *zap.Logger
-		PoolSize         int
+		Log      *zap.Logger
+		PoolSize int
+		// TODO(@fyrchik): add `ContractHash` method to the NetmapClient and remove this parameter.
 		NetmapContract   util.Uint160
+		NetmapClient     *nmWrapper.Wrapper
 		EpochTimer       EpochTimerReseter
-		MorphClient      *client.Client
 		EpochState       EpochState
 		AlphabetState    AlphabetState
 		CleanupEnabled   bool
@@ -105,8 +106,6 @@ func New(p *Params) (*Processor, error) {
 	switch {
 	case p.Log == nil:
 		return nil, errors.New("ir/netmap: logger is not set")
-	case p.MorphClient == nil:
-		return nil, errors.New("ir/netmap: morph client is not set")
 	case p.EpochTimer == nil:
 		return nil, errors.New("ir/netmap: epoch itmer is not set")
 	case p.EpochState == nil:
@@ -141,7 +140,7 @@ func New(p *Params) (*Processor, error) {
 		epochTimer:     p.EpochTimer,
 		epochState:     p.EpochState,
 		alphabetState:  p.AlphabetState,
-		morphClient:    p.MorphClient,
+		netmapClient:   p.NetmapClient,
 		containerWrp:   p.ContainerWrapper,
 		netmapSnapshot: newCleanupTable(p.CleanupEnabled, p.CleanupThreshold),
 		handleNewAudit: p.HandleAudit,
diff --git a/pkg/innerring/processors/netmap/snapshot/netmap.go b/pkg/innerring/processors/netmap/snapshot/netmap.go
deleted file mode 100644
index dbba45785..000000000
--- a/pkg/innerring/processors/netmap/snapshot/netmap.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package snapshot
-
-import (
-	"errors"
-	"fmt"
-
-	"github.com/nspcc-dev/neo-go/pkg/util"
-	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
-	"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
-	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
-)
-
-const getNetmapSnapshotMethod = "netmap"
-
-// Fetch returns current netmap node infos.
-// Consider using pkg/morph/client/netmap for this.
-func Fetch(cli *client.Client, contract util.Uint160) (*netmap.Netmap, error) {
-	rawNetmapStack, err := cli.TestInvoke(contract, getNetmapSnapshotMethod)
-	if err != nil {
-		return nil, err
-	}
-
-	if ln := len(rawNetmapStack); ln != 1 {
-		return nil, errors.New("invalid RPC response")
-	}
-
-	rawNodeInfos, err := client.ArrayFromStackItem(rawNetmapStack[0])
-	if err != nil {
-		return nil, err
-	}
-
-	result := make([]netmap.NodeInfo, 0, len(rawNodeInfos))
-
-	for i := range rawNodeInfos {
-		nodeInfo, err := peerInfoFromStackItem(rawNodeInfos[i])
-		if err != nil {
-			return nil, fmt.Errorf("invalid RPC response: %w", err)
-		}
-
-		result = append(result, *nodeInfo)
-	}
-
-	return netmap.NewNetmap(netmap.NodesFromInfo(result))
-}
-
-func peerInfoFromStackItem(prm stackitem.Item) (*netmap.NodeInfo, error) {
-	node := netmap.NewNodeInfo()
-
-	subItems, err := client.ArrayFromStackItem(prm)
-	if err != nil {
-		return nil, err
-	} else if ln := len(subItems); ln != 1 {
-		return nil, errors.New("invalid RPC response")
-	} else if rawNodeInfo, err := client.BytesFromStackItem(subItems[0]); err != nil {
-		return nil, err
-	} else if err = node.Unmarshal(rawNodeInfo); err != nil {
-		return nil, err
-	}
-
-	return node, nil
-}
diff --git a/pkg/morph/client/balance/client.go b/pkg/morph/client/balance/client.go
index 7e4d3799f..74c6b559f 100644
--- a/pkg/morph/client/balance/client.go
+++ b/pkg/morph/client/balance/client.go
@@ -29,12 +29,18 @@ type Option func(*cfg)
 
 type cfg struct {
 	transferXMethod, // transferX method name for invocation
+	mintMethod,
+	burnMethod,
+	lockMethod,
 	balanceOfMethod, // balanceOf method name for invocation
 	decimalsMethod string // decimals method name for invocation
 }
 
 const (
 	defaultTransferXMethod = "transferX" // default "transferX" method name
+	defaultMintMethod      = "mint"      // default "mint" method name
+	defaultBurnMethod      = "burn"      // default "burn" method name
+	defaultLockMethod      = "lock"      // default "lock" method name
 	defaultBalanceOfMethod = "balanceOf" // default "balance of" method name
 	defaultDecimalsMethod  = "decimals"  // default decimals method name
 )
@@ -42,6 +48,9 @@ const (
 func defaultConfig() *cfg {
 	return &cfg{
 		transferXMethod: defaultTransferXMethod,
+		mintMethod:      defaultMintMethod,
+		burnMethod:      defaultBurnMethod,
+		lockMethod:      defaultLockMethod,
 		balanceOfMethod: defaultBalanceOfMethod,
 		decimalsMethod:  defaultDecimalsMethod,
 	}
diff --git a/pkg/morph/client/balance/transfer.go b/pkg/morph/client/balance/transfer.go
index a24a1eb1b..6f6094e8b 100644
--- a/pkg/morph/client/balance/transfer.go
+++ b/pkg/morph/client/balance/transfer.go
@@ -56,3 +56,18 @@ func (c *Client) TransferX(args TransferXArgs) error {
 
 	return nil
 }
+
+// Mint invokes `mint` method of the balance contract.
+func (c *Client) Mint(to []byte, amount int64, id []byte) error {
+	return c.client.Invoke(c.mintMethod, to, amount, id)
+}
+
+// Burn invokes `burn` method of the balance contract.
+func (c *Client) Burn(to []byte, amount int64, id []byte) error {
+	return c.client.Invoke(c.burnMethod, to, amount, id)
+}
+
+// Lock invokes `lock` method of the balance contract.
+func (c *Client) Lock(id, user, lock []byte, amount, dueEpoch int64) error {
+	return c.client.Invoke(c.lockMethod, id, user, lock, amount, dueEpoch)
+}
diff --git a/pkg/morph/client/balance/wrapper/transfer.go b/pkg/morph/client/balance/wrapper/transfer.go
index 406d39187..f3e01d7fd 100644
--- a/pkg/morph/client/balance/wrapper/transfer.go
+++ b/pkg/morph/client/balance/wrapper/transfer.go
@@ -3,6 +3,7 @@ package wrapper
 import (
 	"fmt"
 
+	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-api-go/pkg/owner"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
 )
@@ -40,3 +41,18 @@ func (w *Wrapper) TransferX(p TransferPrm) error {
 
 	return w.client.TransferX(args)
 }
+
+// Mint sends funds to the account.
+func (w *Wrapper) Mint(to util.Uint160, amount int64, id []byte) error {
+	return w.client.Mint(to.BytesBE(), amount, id)
+}
+
+// Burn destroys funds from the account.
+func (w *Wrapper) Burn(to util.Uint160, amount int64, id []byte) error {
+	return w.client.Burn(to.BytesBE(), amount, id)
+}
+
+// Lock locks fund on the user account.
+func (w *Wrapper) Lock(id []byte, user, lock util.Uint160, amount, dueEpoch int64) error {
+	return w.client.Lock(id, user.BytesBE(), lock.BytesBE(), amount, dueEpoch)
+}
diff --git a/pkg/morph/client/netmap/client.go b/pkg/morph/client/netmap/client.go
index 9afd706ca..f0b001516 100644
--- a/pkg/morph/client/netmap/client.go
+++ b/pkg/morph/client/netmap/client.go
@@ -38,17 +38,21 @@ type cfg struct {
 	epochSnapshotMethod, // get network map snapshot by epoch method name
 	updateStateMethod, // update state method name for invocation
 	epochMethod, // get epoch number method name
+	setInnerRing, // set inner ring method name
+	setConfigMethod, // set config method name
 	configMethod string // get config value method name
 }
 
 const (
-	defaultAddPeerMethod     = "addPeer"     // default add peer method name
-	defaultNewEpochMethod    = "newEpoch"    // default new epoch method name
-	defaultNetMapMethod      = "netmap"      // default get network map method name
-	defaultSnapshotMethod    = "snapshot"    // default get network map snapshot method name
-	defaultUpdateStateMethod = "updateState" // default update state method name
-	defaultEpochMethod       = "epoch"       // default get epoch number method name
-	defaultConfigMethod      = "config"      // default get config value method name
+	defaultAddPeerMethod      = "addPeer"         // default add peer method name
+	defaultNewEpochMethod     = "newEpoch"        // default new epoch method name
+	defaultNetMapMethod       = "netmap"          // default get network map method name
+	defaultSnapshotMethod     = "snapshot"        // default get network map snapshot method name
+	defaultUpdateStateMethod  = "updateState"     // default update state method name
+	defaultEpochMethod        = "epoch"           // default get epoch number method name
+	defaultSetInnerRingMethod = "updateInnerRing" // default set innerring method name
+	defaultSetConfigMethod    = "setConfig"       // default get config value method name
+	defaultConfigMethod       = "config"          // default get config value method name
 
 	defaultEpochSnapshotMethod = "snapshotByEpoch" // default get network map snapshot by epoch method name
 )
@@ -62,6 +66,7 @@ func defaultConfig() *cfg {
 		epochSnapshotMethod: defaultEpochSnapshotMethod,
 		updateStateMethod:   defaultUpdateStateMethod,
 		epochMethod:         defaultEpochMethod,
+		setConfigMethod:     defaultSetConfigMethod,
 		configMethod:        defaultConfigMethod,
 	}
 }
diff --git a/pkg/morph/client/netmap/config.go b/pkg/morph/client/netmap/config.go
index 33e08edc1..f3bc65dd5 100644
--- a/pkg/morph/client/netmap/config.go
+++ b/pkg/morph/client/netmap/config.go
@@ -56,6 +56,11 @@ func (c *Client) Config(args ConfigArgs, assert func(stackitem.Item) (interface{
 	}, nil
 }
 
+// SetConfig invokes `setConfig` method of NeoFS Netmap contract.
+func (c *Client) SetConfig(id, key []byte, value interface{}) error {
+	return c.client.Invoke(c.setConfigMethod, id, key, value)
+}
+
 func IntegerAssert(item stackitem.Item) (interface{}, error) {
 	return client.IntFromStackItem(item)
 }
diff --git a/pkg/morph/client/netmap/innerring.go b/pkg/morph/client/netmap/innerring.go
new file mode 100644
index 000000000..b82ef2a66
--- /dev/null
+++ b/pkg/morph/client/netmap/innerring.go
@@ -0,0 +1,13 @@
+package netmap
+
+import "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
+
+// SetInnerRing updates inner ring members in netmap contract.
+func (c *Client) SetInnerRing(keys keys.PublicKeys) error {
+	args := make([][]byte, len(keys))
+	for i := range args {
+		args[i] = keys[i].Bytes()
+	}
+
+	return c.client.Invoke(c.setInnerRing, args)
+}
diff --git a/pkg/morph/client/netmap/wrapper/config.go b/pkg/morph/client/netmap/wrapper/config.go
index 6270b1b36..77d1a2902 100644
--- a/pkg/morph/client/netmap/wrapper/config.go
+++ b/pkg/morph/client/netmap/wrapper/config.go
@@ -154,3 +154,8 @@ func (w *Wrapper) readStringConfig(key string) (string, error) {
 
 	return str, nil
 }
+
+// SetConfig sets config field.
+func (w *Wrapper) SetConfig(id, key []byte, value interface{}) error {
+	return w.client.SetConfig(id, key, value)
+}
diff --git a/pkg/morph/client/netmap/wrapper/innerring.go b/pkg/morph/client/netmap/wrapper/innerring.go
new file mode 100644
index 000000000..c8007b854
--- /dev/null
+++ b/pkg/morph/client/netmap/wrapper/innerring.go
@@ -0,0 +1,8 @@
+package wrapper
+
+import "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
+
+// SetInnerRing updates inner ring keys.
+func (w *Wrapper) SetInnerRing(keys keys.PublicKeys) error {
+	return w.client.SetInnerRing(keys)
+}
diff --git a/pkg/morph/client/netmap/wrapper/new_epoch.go b/pkg/morph/client/netmap/wrapper/new_epoch.go
index db32f7481..bbe6201cf 100644
--- a/pkg/morph/client/netmap/wrapper/new_epoch.go
+++ b/pkg/morph/client/netmap/wrapper/new_epoch.go
@@ -1,11 +1,12 @@
 package wrapper
 
-// Epoch represents the NeoFS epoch.
-// FIXME: correct the definition.
-type Epoch struct{}
+import "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
 
 // NewEpoch updates NeoFS epoch number through
 // Netmap contract call.
-func (w *Wrapper) NewEpoch(e Epoch) error {
-	panic("implement me")
+func (w *Wrapper) NewEpoch(e uint64) error {
+	var args netmap.NewEpochArgs
+	args.SetEpochNumber(int64(e))
+
+	return w.client.NewEpoch(args)
 }
diff --git a/pkg/morph/client/netmap/wrapper/snapshot.go b/pkg/morph/client/netmap/wrapper/snapshot.go
new file mode 100644
index 000000000..2c5c0397e
--- /dev/null
+++ b/pkg/morph/client/netmap/wrapper/snapshot.go
@@ -0,0 +1,28 @@
+package wrapper
+
+import (
+	"fmt"
+
+	"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
+	netmap2 "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
+)
+
+// Fetch returns current netmap node infos.
+// Consider using pkg/morph/client/netmap for this.
+func (w *Wrapper) Snapshot() (*netmap.Netmap, error) {
+	res, err := w.client.Snapshot(netmap2.GetSnapshotArgs{})
+	if err != nil {
+		return nil, err
+	}
+
+	peers := res.Peers()
+	result := make([]netmap.NodeInfo, len(peers))
+
+	for i := range peers {
+		if err := result[i].Unmarshal(peers[i]); err != nil {
+			return nil, fmt.Errorf("can't unmarshal node info: %w", err)
+		}
+	}
+
+	return netmap.NewNetmap(netmap.NodesFromInfo(result))
+}