public static UInt160 OwnerOf(ByteString tokenId)
        {
            StorageMap nameMap = new(Storage.CurrentContext, Prefix_Name);
            NameState  token   = (NameState)StdLib.Deserialize(nameMap[GetKey(tokenId)]);

            token.EnsureNotExpired();
            return(token.Owner);
        }
        public static Map <string, object> Properties(ByteString tokenId)
        {
            StorageMap nameMap = new(Storage.CurrentContext, Prefix_Name);
            NameState  token   = (NameState)StdLib.Deserialize(nameMap[GetKey(tokenId)]);

            token.EnsureNotExpired();
            Map <string, object> map = new();

            map["name"]       = token.Name;
            map["expiration"] = token.Expiration;
            return(map);
        }
        public static bool Transfer(UInt160 to, ByteString tokenId, object data)
        {
            if (to is null || !to.IsValid)
            {
                throw new Exception("The argument \"to\" is invalid.");
            }
            StorageContext context    = Storage.CurrentContext;
            StorageMap     balanceMap = new(context, Prefix_Balance);
            StorageMap     accountMap = new(context, Prefix_AccountToken);
            StorageMap     nameMap    = new(context, Prefix_Name);
            ByteString     tokenKey   = GetKey(tokenId);
            NameState      token      = (NameState)StdLib.Deserialize(nameMap[tokenKey]);

            token.EnsureNotExpired();
            UInt160 from = token.Owner;

            if (!Runtime.CheckWitness(from))
            {
                return(false);
            }
            if (from != to)
            {
                //Update token info
                token.Owner       = to;
                token.Admin       = null;
                nameMap[tokenKey] = StdLib.Serialize(token);

                //Update from account
                BigInteger balance = (BigInteger)balanceMap[from];
                balance--;
                if (balance.IsZero)
                {
                    balanceMap.Delete(from);
                }
                else
                {
                    balanceMap.Put(from, balance);
                }
                accountMap.Delete(from + tokenKey);

                //Update to account
                balance = (BigInteger)balanceMap[to];
                balance++;
                balanceMap.Put(to, balance);
                accountMap[to + tokenKey] = tokenId;
            }
            PostTransfer(from, to, tokenId, data);
            return(true);
        }