Open lock9 opened 9 months ago
Use primitive types. For example string
not String
.
Map<string, string> myNft = new();
myNft["name"] = "My NFT";
myNft["description"] = "My NFT Description";
var tokenString = myNft;
I did not see the same exception.... tests pass
@Jim8y Its an ApplicationEngine
Error. But It's because of non-primitive types.
I mean, why can't I reproduce the error.
He said
However, if I return the map and print it locally, it works.
So try blockchain?
I'll wait for Rick to explain it.
Hello.
Could it be my compiler version? What version are you using? I'm using Devpack 3.6.2
This doesn't work:
var nftProperties = new Map<string, string>();
nftProperties["key1"] = "value1";
nftProperties["key2"] = "value2";
var nftString = nftProperties.ToString();
This does work:
var nftProperties = new Map<string, string>();
nftProperties["key1"] = "value1";
nftProperties["key2"] = "value2";
var nftString = StdLib.Serialize(nftProperties);
I am using the master of devpack tested your code in one of the test contracts, nothing happens, build and run normally.
I was using the analyzer branch. I switched to the master branch, rebuilt it and got the same results. Is there any chance that the error is in Neo Express?
Here is the file:
using System;
using System.ComponentModel;
using System.Numerics;
using Neo;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Native;
using Neo.SmartContract.Framework.Services;
namespace NFTCollection
{
[DisplayName("CSharpNFT")]
[ManifestExtra("Author", "Linkd Academy")]
[ManifestExtra("Description", "NFT Contract Example")]
[ContractPermission("*", "onNEP11Payment")]
public class NFTCollection : SmartContract
{
static readonly byte[] KeyTotalSupply = { 0x01 };
static readonly byte[] KeyOwner = { 0x02 };
static readonly byte[] PrefixTokenId = { 0x03 };
static readonly byte[] PrefixToken = { 0x04 };
static readonly byte[] PrefixAccountToken = { 0x05 };
static readonly byte[] PrefixBalance = { 0x06 };
public delegate void OnTransferDelegate(UInt160 from, UInt160 to, BigInteger amount, ByteString tokenId);
[DisplayName("Transfer")]
public static event OnTransferDelegate OnTransfer;
[Safe]
public static string Symbol()
{
return "NFTS";
}
[Safe]
public static int Decimals()
{
return 0;
}
[Safe]
public static BigInteger TotalSupply()
{
return (BigInteger)Storage.Get(KeyTotalSupply);
}
[Safe]
public static UInt160 OwnerOf(string tokenId)
{
return (UInt160)Storage.Get(PrefixToken.Concat(tokenId));
}
public class MyNFT
{
public string name;
public string description;
public string tokenId;
public Map<string, string> properties = new Map<string, string>();
}
public static MyNFT CreateNFT()
{
var nftName = "My NFT";
var nftDescription = "My NFT Description";
var nftProperties = new Map<string, string>();
nftProperties["key1"] = "value1";
nftProperties["key2"] = "value2";
var nftString = nftProperties.ToString();
// var nftString = StdLib.Serialize(nftProperties);
// Runtime.Notify("Debug", new object[] { nftString });
// Generate Token ID
var serializedProperties = StdLib.Serialize(nftProperties);
var transactionHash = (Transaction)Runtime.ScriptContainer;
var tokenHashInput = serializedProperties.Concat(transactionHash.Hash);
var tokenId = CryptoLib.Ripemd160(tokenHashInput);
var myNft = new MyNFT()
{
name = nftName,
description = nftDescription,
properties = nftProperties,
tokenId = tokenId
};
return myNft;
}
public static object TestNFT()
{
var transaction = (Transaction)Runtime.ScriptContainer;
var sender = transaction.Sender;
var nft = CreateNFT();
var serializedNFT = StdLib.Serialize(nft);
var tokenDetailsKey = PrefixToken.Concat(nft.tokenId);
//Persist the NFT
Storage.Put(tokenDetailsKey, serializedNFT);
//Persist the owner of the NFT
Storage.Put(PrefixTokenId.Concat(nft.tokenId), sender);
var existingTokens = Storage.Get(PrefixAccountToken.Concat(sender));
List<ByteString> deserializedTokens;
if (existingTokens is null)
{
deserializedTokens = new ByteString[] { };
}
else
{
deserializedTokens = (ByteString[])StdLib.Deserialize(existingTokens);
}
//Persist the NFT in the account
deserializedTokens.Add(nft.tokenId);
Storage.Put(PrefixAccountToken.Concat(sender), StdLib.Serialize(deserializedTokens));
// Update the balance of the sender
var balance = (BigInteger)Storage.Get(PrefixBalance.Concat(sender));
var newBalance = balance + 1;
Storage.Put(PrefixBalance.Concat(sender), newBalance);
//Increase the total supply
var totalSupply = (BigInteger)Storage.Get(KeyTotalSupply);
var newTotalSupply = totalSupply + 1;
Storage.Put(KeyTotalSupply, newTotalSupply);
return nft;
}
public static object Properties(string tokenId)
{
var rawNFT = Storage.Get(PrefixToken.Concat(tokenId));
if (rawNFT is null)
{
throw new Exception("Token does not exist");
}
var nft = (MyNFT)StdLib.Deserialize(rawNFT);
return nft.properties;
}
public static Iterator TokensOf(UInt160 account)
{
if (account is null || !account.IsValid)
throw new Exception("Invalid Parameter.");
var accountKey = PrefixAccountToken.Concat(account);
var tokenIds = (Iterator)StdLib.Deserialize(Storage.Get(accountKey));
return tokenIds;
}
[DisplayName("_deploy")]
public static void Deploy(object data, bool update)
{
if (update) return;
Storage.Put(KeyTotalSupply, 0);
var tx = (Transaction)Runtime.ScriptContainer;
Storage.Put(KeyOwner, tx.Sender);
}
[Safe]
public static BigInteger BalanceOf(UInt160 account)
{
if (account is null || !account.IsValid)
throw new Exception("Invalid Parameter.");
BigInteger balance = (BigInteger)Storage.Get(PrefixBalance.Concat(account));
return balance;
}
public static bool Transfer(UInt160 from, UInt160 to, String tokenId, object data)
{
if (from is null || !from.IsValid)
throw new Exception("Invalid from address.");
if (to is null || !to.IsValid)
throw new Exception("Invalid to address.");
if (!Runtime.CheckWitness(from))
throw new Exception("Invalid Signature");
var tokenOwner = (UInt160)Storage.Get(PrefixTokenId.Concat(tokenId));
if (tokenOwner is null)
throw new Exception("Token does not exist");
if (tokenOwner != from)
throw new Exception("Not Authorized");
if (from == to)
return true;
Storage.Put(PrefixTokenId.Concat(tokenId), to);
Storage.Put(PrefixBalance.Concat(from), BalanceOf(from) - 1);
Storage.Put(PrefixBalance.Concat(to), BalanceOf(to) + 1);
if (ContractManagement.GetContract(to) is not null)
{
Contract.Call(to, "onNEP11Payment", CallFlags.All, from, 1, tokenId, data);
}
OnTransfer(from, to, 1, tokenId);
return true;
}
public static void Update(ByteString nefFile, string manifest, object data)
{
if (Runtime.CheckWitness((UInt160)Storage.Get(KeyOwner)))
ContractManagement.Update(nefFile, manifest, data);
}
}
}
It works fine. Remove the .ToString
. This was on TestNet T5
public static void Test()
{
Map<string, string> myNft = new();
myNft["name"] = "My NFT";
myNft["description"] = "My NFT Description";
var tokenString = myNft;
}
This line is wrong var nftString = nftProperties.ToString();
You can't do that.
It seems that there is a general issue with ToString(). The following code is also causing an error:
public static string TestString()
{
return "Jimmy".ToString();
}
Invoke results:
Gas Consumed: 0.0246507 GAS
Exception: An unhandled exception was thrown. The value 2 is out of range.
Result: [ ]
It seems that there is a general issue with ToString(). The following code is also causing an error:
public static string TestString() { return "Jimmy".ToString(); }
Invoke results: Gas Consumed: 0.0246507 GAS Exception: An unhandled exception was thrown. The value 2 is out of range. Result: [ ]
What don't you understand?
@cschuchardt88 I think what @lock9 want to say is it is normal C# operation, neo should allow it work that way. Not about how to make it work, but how it should work.
Well than say that. After 20 times of telling him why he can't do something. He keeps saying I can't do this.
Well than say that. After 20 times of telling him why he can't do something. He keeps saying I can't do this.
- It shows he doesn't read everything.
- It wastes our time.
Hi @Jim8y , I've looked into the UT that you used. It's not checking the VM State.
Problem: When I call the toString() method in a map, the VM will throw an exception. The problems happen in runtime and not compile time. I'm not sure if this is a compiler error or not (probably is).
Compile and run the following code:
Result:
However, if I return the map and print it locally, it works.