diff --git a/pkg/core/interop/interopnames/names.go b/pkg/core/interop/interopnames/names.go
index b4975e090..c15dba958 100644
--- a/pkg/core/interop/interopnames/names.go
+++ b/pkg/core/interop/interopnames/names.go
@@ -16,6 +16,7 @@ const (
 	SystemCallbackInvoke                     = "System.Callback.Invoke"
 	SystemContractCall                       = "System.Contract.Call"
 	SystemContractCallNative                 = "System.Contract.CallNative"
+	SystemContractCreateMultisigAccount      = "System.Contract.CreateMultisigAccount"
 	SystemContractCreateStandardAccount      = "System.Contract.CreateStandardAccount"
 	SystemContractIsStandard                 = "System.Contract.IsStandard"
 	SystemContractGetCallFlags               = "System.Contract.GetCallFlags"
@@ -70,6 +71,7 @@ var names = []string{
 	SystemCallbackInvoke,
 	SystemContractCall,
 	SystemContractCallNative,
+	SystemContractCreateMultisigAccount,
 	SystemContractCreateStandardAccount,
 	SystemContractIsStandard,
 	SystemContractGetCallFlags,
diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go
index d6ffc3836..11f58482e 100644
--- a/pkg/core/interop_system.go
+++ b/pkg/core/interop_system.go
@@ -4,13 +4,16 @@ import (
 	"crypto/elliptic"
 	"errors"
 	"fmt"
+	"math"
 
 	"github.com/nspcc-dev/neo-go/pkg/core/block"
 	"github.com/nspcc-dev/neo-go/pkg/core/interop"
 	"github.com/nspcc-dev/neo-go/pkg/core/native"
 	"github.com/nspcc-dev/neo-go/pkg/core/state"
 	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
+	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
+	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neo-go/pkg/vm"
 	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@@ -221,6 +224,30 @@ func contractIsStandard(ic *interop.Context) error {
 	return nil
 }
 
+// contractCreateMultisigAccount calculates multisig contract scripthash for a
+// given m and a set of public keys.
+func contractCreateMultisigAccount(ic *interop.Context) error {
+	m := ic.VM.Estack().Pop().BigInt()
+	if !m.IsInt64() || m.Int64() > math.MaxInt32 {
+		return errors.New("m should fit int32")
+	}
+	arr := ic.VM.Estack().Pop().Array()
+	pubs := make(keys.PublicKeys, len(arr))
+	for i, pk := range arr {
+		p, err := keys.NewPublicKeyFromBytes(pk.Value().([]byte), elliptic.P256())
+		if err != nil {
+			return err
+		}
+		pubs[i] = p
+	}
+	script, err := smartcontract.CreateMultiSigRedeemScript(int(m.Int64()), pubs)
+	if err != nil {
+		return err
+	}
+	ic.VM.Estack().PushVal(hash.Hash160(script).BytesBE())
+	return nil
+}
+
 // contractCreateStandardAccount calculates contract scripthash for a given public key.
 func contractCreateStandardAccount(ic *interop.Context) error {
 	h := ic.VM.Estack().Pop().Bytes()
diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go
index 3c03c82fd..5d3ff67f7 100644
--- a/pkg/core/interop_system_test.go
+++ b/pkg/core/interop_system_test.go
@@ -2,6 +2,7 @@ package core
 
 import (
 	"errors"
+	"math"
 	"math/big"
 	"testing"
 
@@ -110,6 +111,53 @@ func TestContractCreateAccount(t *testing.T) {
 	})
 }
 
+func TestContractCreateMultisigAccount(t *testing.T) {
+	v, ic, chain := createVM(t)
+	defer chain.Close()
+	t.Run("Good", func(t *testing.T) {
+		m, n := 3, 5
+		pubs := make(keys.PublicKeys, n)
+		arr := make([]stackitem.Item, n)
+		for i := range pubs {
+			pk, err := keys.NewPrivateKey()
+			require.NoError(t, err)
+			pubs[i] = pk.PublicKey()
+			arr[i] = stackitem.Make(pubs[i].Bytes())
+		}
+		v.Estack().PushVal(stackitem.Make(arr))
+		v.Estack().PushVal(m)
+		require.NoError(t, contractCreateMultisigAccount(ic))
+
+		expected, err := smartcontract.CreateMultiSigRedeemScript(m, pubs)
+		require.NoError(t, err)
+		value := v.Estack().Pop().Bytes()
+		u, err := util.Uint160DecodeBytesBE(value)
+		require.NoError(t, err)
+		require.Equal(t, hash.Hash160(expected), u)
+	})
+	t.Run("InvalidKey", func(t *testing.T) {
+		v.Estack().PushVal(stackitem.Make([]stackitem.Item{stackitem.Make([]byte{1, 2, 3})}))
+		v.Estack().PushVal(1)
+		require.Error(t, contractCreateMultisigAccount(ic))
+	})
+	t.Run("Invalid m", func(t *testing.T) {
+		pk, err := keys.NewPrivateKey()
+		require.NoError(t, err)
+		v.Estack().PushVal(stackitem.Make([]stackitem.Item{stackitem.Make(pk.PublicKey().Bytes())}))
+		v.Estack().PushVal(2)
+		require.Error(t, contractCreateMultisigAccount(ic))
+	})
+	t.Run("m overflows int64", func(t *testing.T) {
+		pk, err := keys.NewPrivateKey()
+		require.NoError(t, err)
+		v.Estack().PushVal(stackitem.Make([]stackitem.Item{stackitem.Make(pk.PublicKey().Bytes())}))
+		m := big.NewInt(math.MaxInt64)
+		m.Add(m, big.NewInt(1))
+		v.Estack().PushVal(stackitem.NewBigInteger(m))
+		require.Error(t, contractCreateMultisigAccount(ic))
+	})
+}
+
 func TestRuntimeGasLeft(t *testing.T) {
 	v, ic, chain := createVM(t)
 	defer chain.Close()
diff --git a/pkg/core/interops.go b/pkg/core/interops.go
index 170696693..021dbb725 100644
--- a/pkg/core/interops.go
+++ b/pkg/core/interops.go
@@ -43,6 +43,7 @@ var systemInterops = []interop.Function{
 	{Name: interopnames.SystemContractCall, Func: contract.Call, Price: 1 << 15,
 		RequiredFlags: callflag.AllowCall, ParamCount: 4},
 	{Name: interopnames.SystemContractCallNative, Func: native.Call, Price: 0, ParamCount: 1},
+	{Name: interopnames.SystemContractCreateMultisigAccount, Func: contractCreateMultisigAccount, Price: 1 << 8, ParamCount: 1},
 	{Name: interopnames.SystemContractCreateStandardAccount, Func: contractCreateStandardAccount, Price: 1 << 8, ParamCount: 1},
 	{Name: interopnames.SystemContractIsStandard, Func: contractIsStandard, Price: 1 << 10, RequiredFlags: callflag.ReadStates, ParamCount: 1},
 	{Name: interopnames.SystemContractGetCallFlags, Func: contractGetCallFlags, Price: 1 << 10},