diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go
index 019f4a7c9..97a841464 100644
--- a/pkg/compiler/analysis.go
+++ b/pkg/compiler/analysis.go
@@ -316,7 +316,7 @@ func canConvert(s string) bool {
 		s = s[len(interopPrefix):]
 		return s != "/iterator.Iterator" && s != "/storage.Context" &&
 			s != "/native/ledger.Block" && s != "/native/ledger.Transaction" &&
-			s != "/native/management.Contract"
+			s != "/native/management.Contract" && s != "/native/neo.AccountState"
 	}
 	return true
 }
diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go
index b26f10813..bf73a1baf 100644
--- a/pkg/compiler/native_test.go
+++ b/pkg/compiler/native_test.go
@@ -116,6 +116,7 @@ func TestNativeHelpersCompile(t *testing.T) {
 		{"vote", []string{u160, pub}},
 		{"unclaimedGas", []string{u160, "123"}},
 		{"unregisterCandidate", []string{pub}},
+		{"getAccountState", []string{u160}},
 	}, nep17TestCases...))
 	runNativeTestCases(t, cs.GAS.ContractMD, "gas", append([]nativeTestCase{
 		{"refuel", []string{u160, "123"}},
diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go
index 1a6af1a16..aad0bc9a7 100644
--- a/pkg/core/native/native_neo.go
+++ b/pkg/core/native/native_neo.go
@@ -20,6 +20,7 @@ import (
 	"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/encoding/bigint"
+	"github.com/nspcc-dev/neo-go/pkg/io"
 	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
 	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
 	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@@ -143,6 +144,11 @@ func newNEO() *NEO {
 	md = newMethodAndPrice(n.getCandidatesCall, 1<<22, callflag.ReadStates)
 	n.AddMethod(md, desc)
 
+	desc = newDescriptor("getAccountState", smartcontract.ArrayType,
+		manifest.NewParameter("account", smartcontract.Hash160Type))
+	md = newMethodAndPrice(n.getAccountState, 1<<15, callflag.ReadStates)
+	n.AddMethod(md, desc)
+
 	desc = newDescriptor("getCommittee", smartcontract.ArrayType)
 	md = newMethodAndPrice(n.getCommittee, 1<<16, callflag.ReadStates)
 	n.AddMethod(md, desc)
@@ -863,6 +869,21 @@ func (n *NEO) getCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackit
 	return stackitem.NewArray(arr)
 }
 
+func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stackitem.Item {
+	key := makeAccountKey(toUint160(args[0]))
+	si := ic.DAO.GetStorageItem(n.ID, key)
+	if len(si) == 0 {
+		return stackitem.Null{}
+	}
+
+	r := io.NewBinReaderFromBuf(si)
+	item := stackitem.DecodeBinaryStackItem(r)
+	if r.Err != nil {
+		panic(r.Err) // no errors are expected but we better be sure
+	}
+	return item
+}
+
 // ComputeNextBlockValidators returns an actual list of current validators.
 func (n *NEO) ComputeNextBlockValidators(bc blockchainer.Blockchainer, d dao.DAO) (keys.PublicKeys, error) {
 	if vals := n.validators.Load().(keys.PublicKeys); vals != nil {
diff --git a/pkg/core/native_neo_test.go b/pkg/core/native_neo_test.go
index 5050681da..f5766d565 100644
--- a/pkg/core/native_neo_test.go
+++ b/pkg/core/native_neo_test.go
@@ -229,6 +229,34 @@ func TestNEO_CalculateBonus(t *testing.T) {
 	})
 }
 
+func TestNEO_GetAccountState(t *testing.T) {
+	bc := newTestChain(t)
+
+	acc, err := wallet.NewAccount()
+	require.NoError(t, err)
+
+	h := acc.Contract.ScriptHash()
+	t.Run("empty", func(t *testing.T) {
+		res, err := invokeContractMethod(bc, 1_0000000, bc.contracts.NEO.Hash, "getAccountState", h)
+		require.NoError(t, err)
+		checkResult(t, res, stackitem.Null{})
+	})
+
+	const amount = 123
+	transferTokenFromMultisigAccountCheckOK(t, bc, h, bc.GoverningTokenHash(), int64(amount))
+
+	t.Run("with funds", func(t *testing.T) {
+		bs := stackitem.NewStruct([]stackitem.Item{
+			stackitem.Make(123),
+			stackitem.Make(bc.BlockHeight()),
+			stackitem.Null{},
+		})
+		res, err := invokeContractMethod(bc, 1_0000000, bc.contracts.NEO.Hash, "getAccountState", h)
+		require.NoError(t, err)
+		checkResult(t, res, bs)
+	})
+}
+
 func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
 	bc := newTestChain(t)
 
diff --git a/pkg/interop/native/neo/neo.go b/pkg/interop/native/neo/neo.go
index b72a16404..44003bbfe 100644
--- a/pkg/interop/native/neo/neo.go
+++ b/pkg/interop/native/neo/neo.go
@@ -11,6 +11,13 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/interop/contract"
 )
 
+// AccountState contains info about NEO holder.
+type AccountState struct {
+	Balance int
+	Height  int
+	VoteTo  interop.PublicKey
+}
+
 // Hash represents NEO contract hash.
 const Hash = "\xf5\x63\xea\x40\xbc\x28\x3d\x4d\x0e\x05\xc4\x8e\xa3\x05\xb3\xf2\xa0\x73\x40\xef"
 
@@ -94,3 +101,8 @@ func Vote(addr interop.Hash160, pub interop.PublicKey) bool {
 func UnclaimedGAS(addr interop.Hash160, end int) int {
 	return contract.Call(interop.Hash160(Hash), "unclaimedGas", contract.ReadStates, addr, end).(int)
 }
+
+// GetAccountState represents `getAccountState` method of NEO native contract.
+func GetAccountState(addr interop.Hash160) *AccountState {
+	return contract.Call(interop.Hash160(Hash), "getAccountState", contract.ReadStates, addr).(*AccountState)
+}