diff --git a/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go b/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go
index fe09776ede..dccd8909f2 100644
--- a/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go
+++ b/cmd/frostfs-adm/internal/modules/morph/ape/ape_util.go
@@ -4,8 +4,6 @@ import (
 	"fmt"
 	"strings"
 
-	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
-	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
 	parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
@@ -91,13 +89,7 @@ func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *ac
 	c, err := helper.GetN3Client(v)
 	commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
 
-	walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
-	wallets, err := helper.GetAlphabetWallets(v, walletDir)
-	commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
-
-	committeeAcc, err := helper.GetWalletAccount(wallets[0], constants.CommitteeAccountName)
-	commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
-
+	committeeAcc := helper.GetComitteAcc(cmd, v)
 	ac, err := helper.NewActor(c, committeeAcc)
 	commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
 
diff --git a/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go b/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go
index 00c2fae6d5..961ceba536 100644
--- a/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go
+++ b/cmd/frostfs-adm/internal/modules/morph/helper/initialize.go
@@ -7,7 +7,9 @@ import (
 
 	"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
 	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
 	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
@@ -101,6 +103,16 @@ func GetWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) {
 	return nil, fmt.Errorf("account for '%s' not found", typ)
 }
 
+func GetComitteAcc(cmd *cobra.Command, v *viper.Viper) *wallet.Account {
+	walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
+	wallets, err := GetAlphabetWallets(v, walletDir)
+	commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
+
+	committeeAcc, err := GetWalletAccount(wallets[0], constants.CommitteeAccountName)
+	commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
+	return committeeAcc
+}
+
 func NNSResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
 	return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
 }
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/helper.go b/cmd/frostfs-adm/internal/modules/morph/nns/helper.go
new file mode 100644
index 0000000000..4c9c9e576f
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/helper.go
@@ -0,0 +1,28 @@
+package nns
+
+import (
+	client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/nns"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
+	"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
+	"github.com/nspcc-dev/neo-go/pkg/util"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+func getRPCClient(cmd *cobra.Command) (*client.Contract, *actor.Actor, util.Uint160) {
+	v := viper.GetViper()
+	c, err := helper.GetN3Client(v)
+	commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
+
+	committeeAcc := helper.GetComitteAcc(cmd, v)
+	ac, err := helper.NewActor(c, committeeAcc)
+	commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
+
+	inv := &ac.Invoker
+	r := management.NewReader(inv)
+	nnsCs, err := r.GetContractByID(1)
+	commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
+	return client.New(ac, nnsCs.Hash), ac, nnsCs.Hash
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/record.go b/cmd/frostfs-adm/internal/modules/morph/nns/record.go
new file mode 100644
index 0000000000..0e217eb616
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/record.go
@@ -0,0 +1,148 @@
+package nns
+
+import (
+	"errors"
+	"math/big"
+	"strings"
+
+	"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
+	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
+	"github.com/spf13/cobra"
+)
+
+func initAddRecordCmd() {
+	Cmd.AddCommand(addRecordCmd)
+	addRecordCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	addRecordCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	addRecordCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+	addRecordCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
+	addRecordCmd.Flags().String(nnsRecordDataFlag, "", nnsRecordDataFlagDesc)
+
+	_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsNameFlag)
+	_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordTypeFlag)
+	_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordDataFlag)
+}
+
+func initGetRecordsCmd() {
+	Cmd.AddCommand(getRecordsCmd)
+	getRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	getRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	getRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+	getRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
+
+	_ = cobra.MarkFlagRequired(getRecordsCmd.Flags(), nnsNameFlag)
+}
+
+func initDelRecordsCmd() {
+	Cmd.AddCommand(delRecordsCmd)
+	delRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	delRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	delRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+	delRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
+
+	_ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsNameFlag)
+	_ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsRecordTypeFlag)
+}
+
+func addRecord(cmd *cobra.Command, _ []string) {
+	c, actor, _ := getRPCClient(cmd)
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	data, _ := cmd.Flags().GetString(nnsRecordDataFlag)
+	recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
+	typ, err := getRecordType(recordType)
+	commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
+	h, vub, err := c.AddRecord(name, typ, data)
+	commonCmd.ExitOnErr(cmd, "unable to add record: %w", err)
+
+	cmd.Println("Waiting for transaction to persist...")
+	_, err = actor.Wait(h, vub, err)
+	commonCmd.ExitOnErr(cmd, "renew domain error: %w", err)
+	cmd.Println("Record added successfully")
+}
+
+func getRecords(cmd *cobra.Command, _ []string) {
+	c, act, hash := getRPCClient(cmd)
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
+	if recordType == "" {
+		sid, r, err := unwrap.SessionIterator(act.Invoker.Call(hash, "getAllRecords", name))
+		commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
+		defer func() {
+			_ = act.Invoker.TerminateSession(sid)
+		}()
+		items, err := act.Invoker.TraverseIterator(sid, &r, 0)
+		commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
+		for len(items) != 0 {
+			for j := range items {
+				rs := items[j].Value().([]stackitem.Item)
+				bs, err := rs[2].TryBytes()
+				commonCmd.ExitOnErr(cmd, "unable to parse record state: %w", err)
+				cmd.Printf("%s %s\n",
+					recordTypeToString(nns.RecordType(rs[1].Value().(*big.Int).Int64())),
+					string(bs))
+			}
+			items, err = act.Invoker.TraverseIterator(sid, &r, 0)
+			commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
+		}
+	} else {
+		typ, err := getRecordType(recordType)
+		commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
+		items, err := c.GetRecords(name, typ)
+		commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
+		for _, item := range items {
+			record, err := item.TryBytes()
+			commonCmd.ExitOnErr(cmd, "unable to parse response: %w", err)
+			cmd.Println(string(record))
+		}
+	}
+}
+
+func delRecords(cmd *cobra.Command, _ []string) {
+	c, actor, _ := getRPCClient(cmd)
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
+	typ, err := getRecordType(recordType)
+	commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
+	h, vub, err := c.DeleteRecords(name, typ)
+	commonCmd.ExitOnErr(cmd, "unable to delete records: %w", err)
+
+	cmd.Println("Waiting for transaction to persist...")
+	_, err = actor.Wait(h, vub, err)
+	commonCmd.ExitOnErr(cmd, "delete records error: %w", err)
+	cmd.Println("Records removed successfully")
+}
+
+func getRecordType(recordType string) (*big.Int, error) {
+	switch strings.ToUpper(recordType) {
+	case "A":
+		return big.NewInt(int64(nns.A)), nil
+	case "CNAME":
+		return big.NewInt(int64(nns.CNAME)), nil
+	case "SOA":
+		return big.NewInt(int64(nns.SOA)), nil
+	case "TXT":
+		return big.NewInt(int64(nns.TXT)), nil
+	case "AAAA":
+		return big.NewInt(int64(nns.AAAA)), nil
+	}
+	return nil, errors.New("unsupported record type")
+}
+
+func recordTypeToString(rt nns.RecordType) string {
+	switch rt {
+	case nns.A:
+		return "A"
+	case nns.CNAME:
+		return "CNAME"
+	case nns.SOA:
+		return "SOA"
+	case nns.TXT:
+		return "TXT"
+	case nns.AAAA:
+		return "AAAA"
+	}
+	return ""
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/register.go b/cmd/frostfs-adm/internal/modules/morph/nns/register.go
new file mode 100644
index 0000000000..d05d9f171a
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/register.go
@@ -0,0 +1,44 @@
+package nns
+
+import (
+	"math/big"
+
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/spf13/cobra"
+)
+
+func initRegisterCmd() {
+	Cmd.AddCommand(registerCmd)
+	registerCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	registerCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	registerCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+	registerCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email")
+	registerCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal, "SOA record REFRESH parameter")
+	registerCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal, "SOA record RETRY parameter")
+	registerCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime), "SOA record EXPIRE parameter")
+	registerCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal, "SOA record TTL parameter")
+
+	_ = cobra.MarkFlagRequired(registerCmd.Flags(), nnsNameFlag)
+}
+
+func registerDomain(cmd *cobra.Command, _ []string) {
+	c, actor, _ := getRPCClient(cmd)
+
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	email, _ := cmd.Flags().GetString(nnsEmailFlag)
+	refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag)
+	retry, _ := cmd.Flags().GetInt64(nnsRetryFlag)
+	expire, _ := cmd.Flags().GetInt64(nnsExpireFlag)
+	ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag)
+
+	h, vub, err := c.Register(name, actor.Sender(), email, big.NewInt(refresh),
+		big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl))
+	commonCmd.ExitOnErr(cmd, "unable to register domain: %w", err)
+
+	cmd.Println("Waiting for transaction to persist...")
+	_, err = actor.Wait(h, vub, err)
+	commonCmd.ExitOnErr(cmd, "register domain error: %w", err)
+	cmd.Println("Domain registered successfully")
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/renew.go b/cmd/frostfs-adm/internal/modules/morph/nns/renew.go
new file mode 100644
index 0000000000..b13092240e
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/renew.go
@@ -0,0 +1,26 @@
+package nns
+
+import (
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/spf13/cobra"
+)
+
+func initRenewCmd() {
+	Cmd.AddCommand(renewCmd)
+	renewCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	renewCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	renewCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+}
+
+func renewDomain(cmd *cobra.Command, _ []string) {
+	c, actor, _ := getRPCClient(cmd)
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	h, vub, err := c.Renew(name)
+	commonCmd.ExitOnErr(cmd, "unable to renew domain: %w", err)
+
+	cmd.Println("Waiting for transaction to persist...")
+	_, err = actor.Wait(h, vub, err)
+	commonCmd.ExitOnErr(cmd, "renew domain error: %w", err)
+	cmd.Println("Domain renewed successfully")
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/root.go b/cmd/frostfs-adm/internal/modules/morph/nns/root.go
new file mode 100644
index 0000000000..09133f9329
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/root.go
@@ -0,0 +1,101 @@
+package nns
+
+import (
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+const (
+	nnsNameFlag           = "name"
+	nnsNameFlagDesc       = "Domain name"
+	nnsEmailFlag          = "email"
+	nnsRefreshFlag        = "refresh"
+	nnsRetryFlag          = "retry"
+	nnsExpireFlag         = "expire"
+	nnsTTLFlag            = "ttl"
+	nnsRecordTypeFlag     = "type"
+	nnsRecordTypeFlagDesc = "Domain name service record type(A|CNAME|SOA|TXT)"
+	nnsRecordDataFlag     = "data"
+	nnsRecordDataFlagDesc = "Domain name service record data"
+)
+
+var (
+	Cmd = &cobra.Command{
+		Use:   "nns",
+		Short: "Section for Neo Name Service (NNS)",
+	}
+	tokensCmd = &cobra.Command{
+		Use:   "tokens",
+		Short: "List all registered domain names",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: listTokens,
+	}
+	registerCmd = &cobra.Command{
+		Use:   "register",
+		Short: "Registers a new domain",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: registerDomain,
+	}
+	renewCmd = &cobra.Command{
+		Use:   "renew",
+		Short: "Increases domain expiration date",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: renewDomain,
+	}
+	updateCmd = &cobra.Command{
+		Use:   "update",
+		Short: "Updates soa record",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: updateSOA,
+	}
+	addRecordCmd = &cobra.Command{
+		Use:   "add-record",
+		Short: "Adds a new record of the specified type to the provided domain",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: addRecord,
+	}
+	getRecordsCmd = &cobra.Command{
+		Use:   "get-records",
+		Short: "Returns domain record of the specified type",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: getRecords,
+	}
+	delRecordsCmd = &cobra.Command{
+		Use:   "delete-records",
+		Short: "Removes domain records with the specified type",
+		PreRun: func(cmd *cobra.Command, _ []string) {
+			_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
+			_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
+		},
+		Run: delRecords,
+	}
+)
+
+func init() {
+	initTokensCmd()
+	initRegisterCmd()
+	initRenewCmd()
+	initUpdateCmd()
+	initAddRecordCmd()
+	initGetRecordsCmd()
+	initDelRecordsCmd()
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go b/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go
new file mode 100644
index 0000000000..6e8ffb40a4
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/tokens.go
@@ -0,0 +1,24 @@
+package nns
+
+import (
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/spf13/cobra"
+)
+
+func initTokensCmd() {
+	Cmd.AddCommand(tokensCmd)
+	tokensCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	tokensCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+}
+
+func listTokens(cmd *cobra.Command, _ []string) {
+	c, _, _ := getRPCClient(cmd)
+	it, err := c.Tokens()
+	commonCmd.ExitOnErr(cmd, "unable to get tokens: %w", err)
+	for toks, err := it.Next(10); err == nil && len(toks) > 0; toks, err = it.Next(10) {
+		for _, token := range toks {
+			cmd.Println(string(token))
+		}
+	}
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/nns/update.go b/cmd/frostfs-adm/internal/modules/morph/nns/update.go
new file mode 100644
index 0000000000..3437316e36
--- /dev/null
+++ b/cmd/frostfs-adm/internal/modules/morph/nns/update.go
@@ -0,0 +1,50 @@
+package nns
+
+import (
+	"math/big"
+
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/spf13/cobra"
+)
+
+func initUpdateCmd() {
+	Cmd.AddCommand(updateCmd)
+	updateCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
+	updateCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
+	updateCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
+	updateCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email")
+	updateCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal,
+		"The number of seconds between update requests from secondary and slave name servers")
+	updateCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal,
+		"The number of seconds the secondary or slave will wait before retrying when the last attempt has failed")
+	updateCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime),
+		"The number of seconds a master or slave will wait before considering the data stale "+
+			"if it cannot reach the primary name server")
+	updateCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal,
+		"The number of seconds a domain name is cached locally before expiration and return to authoritative "+
+			"nameservers for updated information")
+
+	_ = cobra.MarkFlagRequired(updateCmd.Flags(), nnsNameFlag)
+}
+
+func updateSOA(cmd *cobra.Command, _ []string) {
+	c, actor, _ := getRPCClient(cmd)
+
+	name, _ := cmd.Flags().GetString(nnsNameFlag)
+	email, _ := cmd.Flags().GetString(nnsEmailFlag)
+	refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag)
+	retry, _ := cmd.Flags().GetInt64(nnsRetryFlag)
+	expire, _ := cmd.Flags().GetInt64(nnsExpireFlag)
+	ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag)
+
+	h, vub, err := c.UpdateSOA(name, email, big.NewInt(refresh),
+		big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl))
+	commonCmd.ExitOnErr(cmd, "unable to send transaction: %w", err)
+
+	cmd.Println("Waiting for transaction to persist...")
+	_, err = actor.Wait(h, vub, err)
+	commonCmd.ExitOnErr(cmd, "register domain error: %w", err)
+	cmd.Println("SOA records updated successfully")
+}
diff --git a/cmd/frostfs-adm/internal/modules/morph/root.go b/cmd/frostfs-adm/internal/modules/morph/root.go
index 9d2b25cebe..e8426d56e7 100644
--- a/cmd/frostfs-adm/internal/modules/morph/root.go
+++ b/cmd/frostfs-adm/internal/modules/morph/root.go
@@ -10,6 +10,7 @@ import (
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/generate"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/initialize"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/netmap"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/nns"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/node"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/notary"
 	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/policy"
@@ -49,4 +50,5 @@ func init() {
 	RootCmd.AddCommand(proxy.RemoveAccountCmd)
 
 	RootCmd.AddCommand(frostfsid.Cmd)
+	RootCmd.AddCommand(nns.Cmd)
 }