From 951f09bae50c97d6ce2283d74d1dff49333f5f5a Mon Sep 17 00:00:00 2001 From: Sergio Flores Date: Sat, 5 Aug 2023 11:53:36 +0100 Subject: [PATCH 1/4] Refactored Module into partial clas --- .../PublishProfiles/FolderProfile.pubxml | 2 +- Library/src/CodeGen/Libraries.cs | 755 ++++++++++++++++++ Library/src/CodeGen/Module.cs | 750 +---------------- 3 files changed, 757 insertions(+), 750 deletions(-) create mode 100644 Library/src/CodeGen/Libraries.cs diff --git a/Compiler/Properties/PublishProfiles/FolderProfile.pubxml b/Compiler/Properties/PublishProfiles/FolderProfile.pubxml index 1523c5e..7d18c78 100644 --- a/Compiler/Properties/PublishProfiles/FolderProfile.pubxml +++ b/Compiler/Properties/PublishProfiles/FolderProfile.pubxml @@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Any CPU C:\Code\TOMB\Publish\ FileSystem - net6.0 + net7.0 false \ No newline at end of file diff --git a/Library/src/CodeGen/Libraries.cs b/Library/src/CodeGen/Libraries.cs new file mode 100644 index 0000000..204aee3 --- /dev/null +++ b/Library/src/CodeGen/Libraries.cs @@ -0,0 +1,755 @@ +using Phantasma.Business.Blockchain.Contracts.Native; +using Phantasma.Core.Domain; +using Phantasma.Core.Numerics; +using Phantasma.Tomb.AST; +using Phantasma.Tomb.AST.Declarations; +using Phantasma.Tomb.AST.Expressions; + +namespace Phantasma.Tomb.CodeGen +{ + public partial class Module + { + public void ImportLibrary(string name) + { + var lib = LoadLibrary(name, this.Scope, this.Kind); + Libraries[lib.Name] = lib; + } + + public static string[] AvailableLibraries = new[] { + "Call", "Runtime", "Math","Token", "NFT", "Organization", "Oracle", "Storage", "Contract", "Array", + "Leaderboard", "Market", "Account", "Crowdsale", "Stake", "Governance", "Relay", "Mail", + "Time", "Task", "UID", "Map", "List", "String", "Bytes", "Decimal", "Enum", "Address", "Module", FormatLibraryName }; + + public const string FormatLibraryName = "Format"; + + private static void GenerateCasts(LibraryDeclaration libDecl, VarKind baseType, VarKind[] types) + { + foreach (var kind in types) + { + if (kind == VarKind.Bytes) + { + throw new CompilerException("Don't try to generate toBytes, it will be automatically generated"); + } + + var castName = "to" + kind; + + if (Compiler.DebugMode) + { + Console.WriteLine($"Found cast: {baseType}.{castName}()"); + } + + libDecl.AddMethod(castName, MethodImplementationType.Custom, kind, new[] { new MethodParameter("target", baseType) }). + SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(kind); + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"CAST {reg} {reg} #{vmType}"); + return reg; + }); + } + } + + public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKind moduleKind) + { + if (name != name.UppercaseFirst() && name != "this") + { + throw new CompilerException("invalid library name: " + name); + } + + var libDecl = new LibraryDeclaration(scope, name); + + Builtins.FillLibrary(libDecl); + + VarKind libKind; + if (Enum.TryParse(name, out libKind) && libKind != VarKind.Bytes && libKind != VarKind.Method && libKind != VarKind.Task && libKind != VarKind.Array) + { + switch (libKind) + { + case VarKind.Decimal: + case VarKind.Struct: + case VarKind.Module: + libKind = VarKind.Any; + break; + } + + libDecl.AddMethod("toBytes", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", libKind) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.Bytes}"); + return reg; + }); + } + + switch (name) + { + case "Module": + libDecl.AddMethod("getScript", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module) }). + SetPreCallback((output, scope, expr) => + { + var reg = Compiler.Instance.AllocRegister(output, expr); + var module = expr.arguments[0].AsLiteral(); + var script = Base16.Encode(module.script); + output.AppendLine(expr, $"LOAD {reg} 0x{script}"); + return reg; + }); + + libDecl.AddMethod("getABI", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module) }). + SetPreCallback((output, scope, expr) => + { + var reg = Compiler.Instance.AllocRegister(output, expr); + var module = expr.arguments[0].AsLiteral(); + var abiBytes = module.abi.ToByteArray(); + var script = Base16.Encode(abiBytes); + output.AppendLine(expr, $"LOAD {reg} 0x{script}"); + return reg; + }); + + return libDecl; + + case "Struct": + libDecl.AddMethod("fromBytes", MethodImplementationType.Custom, VarKind.Struct, new[] { new MethodParameter("source", VarKind.Bytes) }); + return libDecl; + + case "String": + // NOTE those are builtins, so they are no longer declared here + //libDecl.AddMethod("toUpper", MethodImplementationType.LocalCall, VarKind.String, new[] { new MethodParameter("s", VarKind.String) }).SetAlias("string_upper"); + //libDecl.AddMethod("toLower", MethodImplementationType.LocalCall, VarKind.String, new[] { new MethodParameter("s", VarKind.String) }).SetAlias("string_lower"); + + libDecl.AddMethod("length", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.String) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"SIZE {reg} {reg}"); + return reg; + }); + + libDecl.AddMethod("substr", MethodImplementationType.Custom, VarKind.String, new[] { new MethodParameter("target", VarKind.String), new MethodParameter("index", VarKind.Number), new MethodParameter("length", VarKind.Number) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + var regB = expr.arguments[1].GenerateCode(output); + var regC = expr.arguments[2].GenerateCode(output); + output.AppendLine(expr, $"RANGE {reg} {reg} {regB} {regC}"); + Compiler.Instance.DeallocRegister(ref regB); + Compiler.Instance.DeallocRegister(ref regC); + return reg; + }); + + libDecl.AddMethod("toArray", MethodImplementationType.Custom, VarType.Find(VarKind.Array, VarType.Find(VarKind.Number)), new[] { new MethodParameter("target", VarKind.String) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.Struct}"); + return reg; + }); + + libDecl.AddMethod("fromArray", MethodImplementationType.Custom, VarKind.String, new[] { new MethodParameter("target", VarType.Find(VarKind.Array, VarType.Find(VarKind.Number))) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.String}"); + return reg; + }); + + GenerateCasts(libDecl, VarKind.String, new VarKind[] { VarKind.Bool, VarKind.Number }); + + return libDecl; + + case "Bytes": + GenerateCasts(libDecl, VarKind.Bytes, new VarKind[] { VarKind.Bool, VarKind.String, VarKind.Number }); + return libDecl; + + case "Number": + GenerateCasts(libDecl, VarKind.Number, new VarKind[] { VarKind.String, VarKind.Timestamp, VarKind.Bool }); + return libDecl; + + case "Hash": + GenerateCasts(libDecl, VarKind.Hash, new VarKind[] { VarKind.String, VarKind.Number }); + return libDecl; + + case "Enum": + GenerateCasts(libDecl, VarKind.Enum, new VarKind[] { VarKind.String, VarKind.Number }); + + libDecl.AddMethod("isSet", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Enum), new MethodParameter("flag", VarKind.Enum) }). + SetPreCallback((output, scope, expr) => + { + var regA = expr.arguments[0].GenerateCode(output); + var regB = expr.arguments[1].GenerateCode(output); + + output.AppendLine(expr, $"AND {regA} {regB} {regA}"); + + Compiler.Instance.DeallocRegister(ref regB); + return regA; + }); + return libDecl; + + + case "Decimal": + libDecl.AddMethod("decimals", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.Any) }). + SetPreCallback((output, scope, expr) => + { + var reg = Compiler.Instance.AllocRegister(output, expr); + var arg = expr.arguments[0]; + var decType = (DecimalVarType)arg.ResultType; + output.AppendLine(expr, $"LOAD {reg} {decType.decimals}"); + return reg; + }); + + libDecl.AddMethod("convert", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("decimalPlaces", VarKind.Number), new MethodParameter("value", VarKind.Number) }). + SetPreCallback((output, scope, expr) => + { + var regA = expr.arguments[0].GenerateCode(output); + var regB = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {regB} 10"); + output.AppendLine(expr, $"POW {regB} {regA} {regA}"); + + Compiler.Instance.DeallocRegister(ref regB); + + regB = expr.arguments[1].GenerateCode(output); + output.AppendLine(expr, $"MUL {regB} {regA} {regA}"); + Compiler.Instance.DeallocRegister(ref regB); + + return regA; + }); + return libDecl; + + case "Array": + { + libDecl.AddMethod("length", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.Any) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"COUNT {reg} {reg}"); + return reg; + }); + + return libDecl; + } + + + case "Address": + // TODO implementations of those + libDecl.AddMethod("isNull", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); + libDecl.AddMethod("isUser", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); + libDecl.AddMethod("isSystem", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); + libDecl.AddMethod("isInterop", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); + + GenerateCasts(libDecl, VarKind.Bytes, new VarKind[] { VarKind.String }); + + return libDecl; + } + + if (moduleKind == ModuleKind.Description) + { + switch (name) + { + case FormatLibraryName: + libDecl.AddMethod("decimals", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("value", VarKind.Number), new MethodParameter("symbol", VarKind.String) }); + libDecl.AddMethod("symbol", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("symbol", VarKind.String) }); + libDecl.AddMethod("account", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("address", VarKind.Address) }); + break; + + default: + throw new CompilerException("unknown library: " + name); + } + + return libDecl; + } + + switch (name) + { + case "Call": + libDecl.AddMethod("interop", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); + libDecl.AddMethod("contract", MethodImplementationType.ContractCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); + libDecl.AddMethod("method", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("method", VarKind.Method), new MethodParameter("...", VarKind.Any) }). + SetPreCallback((output, scope, expr) => + { + var contract = scope.Module as Contract; + if (contract == null) + { + throw new CompilerException("Cannot use Call.method outside of a contract"); + } + + var methodName = expr.arguments[0].AsLiteral(); + var method = contract.FindMethod(methodName); + if (method == null) + { + throw new CompilerException($"Cannot find local method '{methodName}' in contract '{contract.Name}'"); + } + + var label = method.GetEntryLabel(); + + // push the method arguments into the stack, in the proper order + for (int i = expr.arguments.Count - 1; i >= 1; i--) + { + var argReg = expr.arguments[i].GenerateCode(output); + output.AppendLine(expr, $"PUSH {argReg}"); + Compiler.Instance.DeallocRegister(ref argReg); + } + + var reg = Compiler.Instance.AllocRegister(output, expr, expr.NodeID); + output.AppendLine(expr, $"CALL @{label}"); + output.AppendLine(expr, $"POP {reg}"); + return reg; + }); + break; + + case "Chain": + { + libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("source", VarKind.Address), new MethodParameter("organization", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("parentName", VarKind.String) }).SetAlias("Nexus.CreateChain"); + break; + } + + case "Cryptography": + { + libDecl.AddMethod("AESDecrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESDecrypt"); + libDecl.AddMethod("AESEncrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESEncrypt"); + break; + } + + case "Platform": + { + libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("source", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("externalAddress", VarKind.String), new MethodParameter("interopAddress", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Nexus.CreatePlatform"); + libDecl.AddMethod("setTokenHash", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("platform", VarKind.String), new MethodParameter("hash", VarKind.Bytes) }).SetAlias("Nexus.SetTokenPlatformHash"); + break; + } + + case "Runtime": + libDecl.AddMethod("expect", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("condition", VarKind.Bool), new MethodParameter("error", VarKind.String) }). + SetPreCallback((output, scope, expr) => + { + var reg = expr.arguments[0].GenerateCode(output); + output.AppendLine(expr, $"JMPIF {reg} @expect_{expr.NodeID}"); + + var reg2 = expr.arguments[1].GenerateCode(output); + output.AppendLine(expr, $"THROW {reg2}"); + + Compiler.Instance.DeallocRegister(ref reg2); + + output.AppendLine(expr, $"@expect_{expr.NodeID}: NOP"); + return reg; + }); + libDecl.AddMethod("log", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("message", VarKind.String) }); + libDecl.AddMethod("isWitness", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address) }); + libDecl.AddMethod("isTrigger", MethodImplementationType.ExtCall, VarKind.Bool, new MethodParameter[] { }); + libDecl.AddMethod("transactionHash", MethodImplementationType.ExtCall, VarKind.Hash, new MethodParameter[] { }); + libDecl.AddMethod("deployContract", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("contract", VarKind.Module) }).SetParameterCallback("contract", ConvertFieldToContractWithName); + libDecl.AddMethod("upgradeContract", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("contract", VarKind.Module) }).SetParameterCallback("contract", ConvertFieldToContractWithName); + libDecl.AddMethod("gasTarget", MethodImplementationType.ExtCall, VarKind.Address, new MethodParameter[] { }).SetAlias("Runtime.GasTarget"); + libDecl.AddMethod("context", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.Context"); + libDecl.AddMethod("previousContext", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.PreviousContext"); + libDecl.AddMethod("version", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { }).SetAlias("Runtime.Version"); + libDecl.AddMethod("getGovernanceValue", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { new MethodParameter("tag", VarKind.String) }).SetAlias("Nexus.GetGovernanceValue"); + break; + + case "Task": + libDecl.AddMethod("start", MethodImplementationType.ExtCall, VarKind.Task, new MethodParameter[] { new MethodParameter("method", VarKind.Method), new MethodParameter("from", VarKind.Address), new MethodParameter("frequency", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TaskMode")), new MethodParameter("gasLimit", VarKind.Number) }).SetAlias("Task.Start"); + libDecl.AddMethod("stop", MethodImplementationType.ExtCall, VarKind.None, new MethodParameter[] { new MethodParameter("task", VarKind.Address) }).SetAlias("Task.Stop"); + libDecl.AddMethod("current", MethodImplementationType.ExtCall, VarKind.Task, new MethodParameter[] { }).SetAlias("Task.Current"); + break; + + case "Math": + libDecl.AddMethod("min", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("valA", VarKind.Number), new MethodParameter("valB", VarKind.Number) }). + SetPreCallback((output, scope, expr) => + { + var regA = expr.arguments[0].GenerateCode(output); + var regB = expr.arguments[1].GenerateCode(output); + output.AppendLine(expr, $"MIN {regA} {regA} {regB}"); + Compiler.Instance.DeallocRegister(ref regB); + return regA; + }); + + libDecl.AddMethod("max", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("valA", VarKind.Number), new MethodParameter("valB", VarKind.Number) }). + SetPreCallback((output, scope, expr) => + { + var regA = expr.arguments[0].GenerateCode(output); + var regB = expr.arguments[1].GenerateCode(output); + output.AppendLine(expr, $"MAX {regA} {regA} {regB}"); + Compiler.Instance.DeallocRegister(ref regB); + return regA; + }); + + // NOTE those are builtins, so they are no longer declared here + //libDecl.AddMethod("sqrt", MethodImplementationType.LocalCall, VarKind.Number, new[] { new MethodParameter("n", VarKind.Number) }).SetAlias("math_sqrt"); + break; + + case "Time": + GenerateCasts(libDecl, VarKind.Timestamp, new VarKind[] { VarKind.String, VarKind.Number }); + + libDecl.AddMethod("now", MethodImplementationType.ExtCall, VarKind.Timestamp, new MethodParameter[] { }).SetAlias("Runtime.Time"); + libDecl.AddMethod("unix", MethodImplementationType.Custom, VarKind.Timestamp, new[] { new MethodParameter("value", VarKind.Number) }).SetPostCallback((output, scope, method, reg) => + { + var nameExpr = method.arguments[0] as LiteralExpression; + if (nameExpr != null && nameExpr.type.Kind == VarKind.Number) + { + var timestamp = uint.Parse(nameExpr.value); + output.AppendLine(method, $"LOAD {reg} {timestamp}"); + method.CallNecessaryConstructors(output, VarKind.Timestamp, reg); + return reg; + } + else + { + throw new Exception("Expected literal number expression"); + } + }); + break; + + case "Account": + { + libDecl.AddMethod("getName", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { new MethodParameter("from", VarKind.Address) }).SetAlias("Account.Name"); + libDecl.AddMethod("getLastActivity", MethodImplementationType.ExtCall, VarKind.Timestamp, new MethodParameter[] { new MethodParameter("from", VarKind.Address) }).SetAlias("Account.LastActivity"); + var contract = NativeContractKind.Account.ToString().ToLower(); + libDecl.AddMethod("registerName", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(AccountContract.RegisterName)); + libDecl.AddMethod("unregisterName", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.UnregisterName)); + libDecl.AddMethod("registerScript", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("script", VarKind.Bytes), new MethodParameter("abiBytes", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(AccountContract.RegisterScript)); + libDecl.AddMethod("hasScript", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.HasScript)); + //libDecl.AddMethod("lookUpAddress", MethodImplementationType.ContractCall, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpAddress)); + libDecl.AddMethod("lookUpScript", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpScript)); + libDecl.AddMethod("lookUpABI", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpABI)); + libDecl.AddMethod("lookUpName", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpName)); + libDecl.AddMethod("migrate", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.Migrate)); + // TODO ContractMethod GetTriggerForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("trigger", VarKind.Struct) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); + // TODO IEnumerable GetTriggersForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("triggers", VarKind.Struct) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); + // TODO IEnumerable GetTriggersForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("triggers", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); + break; + } + + case "UID": + { + libDecl.AddMethod("generate", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { }).SetAlias("Runtime.GenerateUID"); + break; + } + + case "Random": + // NOTE those are builtins, so they are no longer declared here + //libDecl.AddMethod("generate", MethodImplementationType.LocalCall, VarKind.Number, new MethodParameter[] { }).SetAlias("random_generate"); + //libDecl.AddMethod("seed", MethodImplementationType.LocalCall, VarKind.None, new[] { new MethodParameter("seed", VarKind.Number) }).SetAlias("random_seed"); + break; + + case "Token": + libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("decimals", VarKind.Number), new MethodParameter("flags", VarType.Find(VarKind.Enum, "TokenFlags")), new MethodParameter("script", VarKind.Bytes), new MethodParameter("abi", VarKind.Bytes) }).SetAlias("Nexus.CreateToken"); + libDecl.AddMethod("exists", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.TokenExists"); + libDecl.AddMethod("getDecimals", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenDecimals"); + libDecl.AddMethod("getFlags", MethodImplementationType.ExtCall, VarType.Find(VarKind.Enum, "TokenFlag"), new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenFlags"); + libDecl.AddMethod("transfer", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.TransferTokens"); + libDecl.AddMethod("transferAll", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.TransferBalance"); + libDecl.AddMethod("mint", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.MintTokens"); + libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("token ID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken"); + libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.BurnTokens"); + libDecl.AddMethod("swap", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("targetChain", VarKind.String), new MethodParameter("source", VarKind.Address), new MethodParameter("destination", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.SwapTokens"); + libDecl.AddMethod("getBalance", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetBalance"); + libDecl.AddMethod("isMinter", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.IsMinter"); + libDecl.AddMethod("getCurrentSupply", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenSupply"); + libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableTokenSymbols"); + break; + + case "NFT": + libDecl.AddMethod("transfer", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.TransferToken"); + libDecl.AddMethod("mint", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("rom", VarKind.Any), new MethodParameter("ram", VarKind.Any), new MethodParameter("seriesID", VarKind.Any) }) + .SetParameterCallback("rom", ConvertFieldToBytes).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.MintToken"); + libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken"); + libDecl.AddMethod("readROM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenROM").SetPostCallback(ConvertGenericResult); + libDecl.AddMethod("readRAM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenRAM").SetPostCallback(ConvertGenericResult); + libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.BurnToken"); + libDecl.AddMethod("infuse", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number), new MethodParameter("infuseSymbol", VarKind.String), new MethodParameter("infuseValue", VarKind.Number) }).SetAlias("Runtime.InfuseToken"); + + libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableNFTSymbols"); + + libDecl.AddMethod("createSeries", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("seriesID", VarKind.Number), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TokenSeries")), new MethodParameter("nft", VarKind.Module) }). + SetAlias("Nexus.CreateTokenSeries").SetParameterCallback("nft", ConvertFieldToContractWithoutName); + + libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarType.Find(VarKind.Struct, "NFT"), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadToken") + .SetPreCallback((output, scope, expr) => + { + var nftStruct = VarType.Find(VarKind.Struct, "NFT") as StructVarType; + var reg = Compiler.Instance.AllocRegister(output, expr); + + var fields = '\"' + string.Join(',', nftStruct.decl.fields.Select(x => x.name)) + '\"'; + + output.AppendLine(expr, $"LOAD {reg} {fields} // field list"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback((output, scope, method, reg) => + { + output.AppendLine(method, $"UNPACK {reg} {reg}"); + return reg; + }); + break; + + case "Organization": + { + libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("id", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("script", VarKind.Bytes) }).SetAlias("Nexus.CreateOrganization"); + libDecl.AddMethod("addMember", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("target", VarKind.Address) }); + break; + } + + case "Oracle": + { + libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("url", VarKind.String) }); + libDecl.AddMethod("price", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String) }); + libDecl.AddMethod("quote", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }); + break; + } + + case "Storage": + { + libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("field", VarKind.String) }).SetAlias("Data.Get") + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback(ConvertGenericResult); + + libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("field", VarKind.String), new MethodParameter("value", VarKind.Any) }).SetAlias("Data.Set"); + libDecl.AddMethod("delete", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("field", VarKind.String) }).SetAlias("Data.Delete"); + var contract = NativeContractKind.Storage.ToString().ToLower(); + libDecl.AddMethod("calculateStorageSizeForStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StorageContract.CalculateStorageSizeForStake)); + libDecl.AddMethod("createFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("fileName", VarKind.String), new MethodParameter("fileSize", VarKind.Number), new MethodParameter("contentMerkle", VarKind.Bytes), new MethodParameter("encryptionContent", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.CreateFile)); + libDecl.AddMethod("hasFile", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("hash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.HasFile)); + libDecl.AddMethod("addFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("archiveHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.AddFile)); + libDecl.AddMethod("deleteFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("targetHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.DeleteFile)); + libDecl.AddMethod("hasPermission", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("external", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.HasPermission)); + libDecl.AddMethod("addPermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("externalAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.AddPermission)); + libDecl.AddMethod("deletePermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("externalAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.DeletePermission)); + //libDecl.AddMethod("migratePermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("oldAddr", VarKind.Address), new MethodParameter("newAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.MigratePermission)); + //libDecl.AddMethod("migrate", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.Migrate)); + libDecl.AddMethod("getUsedSpace", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetUsedSpace)); + libDecl.AddMethod("getAvailableSpace", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetAvailableSpace)); + // TODO Hash[] GetFiles(Address from) -> libDecl.AddMethod("getFiles", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetFiles)); + libDecl.AddMethod("getUsedDataQuota", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetUsedDataQuota)); + //libDecl.AddMethod("writeData", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("key", VarKind.Bytes), new MethodParameter("value", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.WriteData)); + //libDecl.AddMethod("deleteData", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("key", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.DeleteData)); + + break; + } + + case "Contract": + libDecl.AddMethod("call", MethodImplementationType.ContractCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); + libDecl.AddMethod("exists", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("name", VarKind.String) }).SetAlias("Runtime.ContractExists"); + + libDecl.AddMethod("address", MethodImplementationType.Custom, VarKind.Address, new[] { new MethodParameter("name", VarKind.String) }).SetPostCallback((output, scope, method, reg) => + { + var nameExpr = method.arguments[0] as LiteralExpression; + if (nameExpr != null && nameExpr.type.Kind == VarKind.String) + { + var address = SmartContract.GetAddressFromContractName(nameExpr.value); + var hex = Base16.Encode(address.ToByteArray()); + output.AppendLine(method, $"LOAD {reg} 0x{hex}"); + return reg; + } + else + { + throw new Exception("Expected literal string expression"); + } + }); + break; + + case "Leaderboard": + { + var contract = NativeContractKind.Ranking.ToString().ToLower(); + libDecl.AddMethod("exists", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("boardName", VarKind.String) }).SetContract(contract).SetAlias(nameof(RankingContract.Exists)); + libDecl.AddMethod("create", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("boardName", VarKind.String), new MethodParameter("capacity", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.CreateLeaderboard)); + libDecl.AddMethod("getAddress", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.GetAddressByIndex)); + libDecl.AddMethod("getScoreByIndex", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.GetScoreByIndex)); + libDecl.AddMethod("getScoreByAddress", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RankingContract.GetScoreByAddress)); + libDecl.AddMethod("getSize", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String) }).SetContract(contract).SetAlias(nameof(RankingContract.GetSize)); + libDecl.AddMethod("insert", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("boardName", VarKind.String), new MethodParameter("score", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.InsertScore)); + libDecl.AddMethod("reset", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("boardName", VarKind.String) }).SetContract(contract).SetAlias(nameof(RankingContract.ResetLeaderboard)); + break; + } + + case "Market": + { + var contract = NativeContractKind.Market.ToString().ToLower(); + libDecl.AddMethod("sell", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endDate", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(MarketContract.SellToken)); + libDecl.AddMethod("buy", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.BuyToken)); + libDecl.AddMethod("cancel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.CancelSale)); + libDecl.AddMethod("hasAuction", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.HasAuction)); + libDecl.AddMethod("bid", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("buyingFee", VarKind.Number), new MethodParameter("buyingFeeAddress", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MarketContract.BidToken)); + // TODO GetAuction -> libDecl.AddMethod("getAuction", MethodImplementationType.ContractCall, VarType.Find(VarKind.Struct, "MarketAuction"), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number)}).SetContract(contract).SetAlias(nameof(MarketContract.GetAuction)); + // TODO GetAuctions -> libDecl.AddMethod("getAuctions", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_list, "MarketAuction"), new[] {} ).SetContract(contract).SetAlias(nameof(MarketContract.GetAuctions)); + libDecl.AddMethod("listToken", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endPrice", VarKind.Number), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("extensionPeriod", VarKind.Number), new MethodParameter("typeAuction", VarKind.Number), new MethodParameter("listingFee", VarKind.Number), new MethodParameter("listingFeeAddress", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MarketContract.ListToken)); + libDecl.AddMethod("editAuction", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endPrice", VarKind.Number), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("extensionPeriod", VarKind.Number), }).SetContract(contract).SetAlias(nameof(MarketContract.EditAuction)); + break; + } + + case "Array": + libDecl.AddMethod("get", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }) + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback(ConvertGenericResult); + + // TODO not implemented yet... for now use builtin TOMB array support, eg: local temp: array + libDecl.AddMethod("set", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }); + libDecl.AddMethod("remove", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }); + libDecl.AddMethod("clear", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any) }); + libDecl.AddMethod("count", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("array", VarKind.Any) }); + break; + + + case "Map": + libDecl.AddMethod("get", MethodImplementationType.ExtCall, VarType.Generic(1), new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead) + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback(ConvertGenericResult); + libDecl.AddMethod("set", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)), new MethodParameter("value", VarType.Generic(1)) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("remove", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("clear", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("count", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("map", VarKind.String) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead); + libDecl.AddMethod("has", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead) + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }); + break; + + case "List": + libDecl.AddMethod("get", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetParameterCallback("list", ConvertFieldToStorageAccessRead) + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback(ConvertGenericResult); + + libDecl.AddMethod("add", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("value", VarType.Generic(0)) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("replace", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("removeAt", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); + libDecl.AddMethod("count", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("list", VarKind.String) }).SetParameterCallback("list", ConvertFieldToStorageAccessRead); + libDecl.AddMethod("clear", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); + break; + + case "Crowdsale": + { + var contract = NativeContractKind.Sale.ToString().ToLower(); + // TODO GetSales -> libDecl.AddMethod("getSales", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "SaleInfo"), new MethodParameter[] { } ).SetContract(contract).SetAlias(nameof(SaleContract.GetSales)); + // TODO GetSale -> libDecl.AddMethod("getSale", MethodImplementationType.ContractCall, VarType.Find(VarKind.Struct, "SaleInfo"), new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSale)); + libDecl.AddMethod("isSeller", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.IsSeller)); + libDecl.AddMethod("isSaleActive", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.IsSaleActive)); + libDecl.AddMethod("create", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("flags", VarKind.Struct), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("sellSymbol", VarKind.String), new MethodParameter("receiveSymbol", VarKind.String), new MethodParameter("price", VarKind.Number), new MethodParameter("globalSoftCap", VarKind.Number), new MethodParameter("globalHardCap", VarKind.Number), new MethodParameter("userSoftCap", VarKind.Number), new MethodParameter("userHardCap", VarKind.Number) }).SetContract(contract).SetAlias(nameof(SaleContract.CreateSale)); // TODO + // TODO getSaleParticipants -> libDecl.AddMethod("getSaleParticipants", MethodImplementationType.ContractCall, VarKind.Storage_List, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSaleParticipants)); + // TODO getSaleWhitelists -> libDecl.AddMethod("getSaleWhitelists", MethodImplementationType.ContractCall, VarKind.Storage_List, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSaleWhitelists)); + libDecl.AddMethod("isWhitelisted", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.IsWhitelisted)); + libDecl.AddMethod("addToWhitelist", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.AddToWhitelist)); + libDecl.AddMethod("removeFromWhitelist", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.RemoveFromWhitelist)); + libDecl.AddMethod("getPurchasedAmount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.GetPurchasedAmount)); + libDecl.AddMethod("getSoldAmount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSoldAmount)); + libDecl.AddMethod("purchase", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("quoteAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(SaleContract.Purchase)); + libDecl.AddMethod("closeSale", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); + libDecl.AddMethod("getLatestSaleHash", MethodImplementationType.ContractCall, VarKind.Hash, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); + libDecl.AddMethod("editSalePrice", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("price", VarKind.Number) }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); + break; + } + + case "Stake": + { + var contract = NativeContractKind.Stake.ToString().ToLower(); + libDecl.AddMethod("getMasterThreshold", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterThreshold)); + libDecl.AddMethod("isMaster", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.IsMaster)); + libDecl.AddMethod("getMasterCount", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterCount)); + libDecl.AddMethod("getMasterAddresses", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterCount)); + libDecl.AddMethod("getClaimMasterCount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("claimDate", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(StakeContract.GetClaimMasterCount)); + libDecl.AddMethod("getMasterClaimDate", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("claimDistance", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterClaimDate)); + libDecl.AddMethod("getMasterDate", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterDate)); + libDecl.AddMethod("getMasterClaimDateFromReference", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("claimDistance", VarKind.Number), new MethodParameter("referenceTime", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterClaimDateFromReference)); + libDecl.AddMethod("getMasterRewards", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterRewards)); + libDecl.AddMethod("masterClaim", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.MasterClaim)); + libDecl.AddMethod("stake", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.Stake)); + libDecl.AddMethod("unstake", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("unstakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.Unstake)); + libDecl.AddMethod("getTimeBeforeUnstake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetTimeBeforeUnstake)); + libDecl.AddMethod("getStakeTimestamp", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStakeTimestamp)); + libDecl.AddMethod("getUnclaimed", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetUnclaimed)); + libDecl.AddMethod("claim", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("stakeAddress", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.Claim)); + libDecl.AddMethod("getStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStake)); + libDecl.AddMethod("getStorageStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStorageStake)); + libDecl.AddMethod("fuelToStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("fuelAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.FuelToStake)); + libDecl.AddMethod("stakeToFuel", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.StakeToFuel)); + libDecl.AddMethod("getAddressVotingPower", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetAddressVotingPower)); + break; + } + + case "Governance": + { + var contract = NativeContractKind.Governance.ToString().ToLower(); + libDecl.AddMethod("hasName", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.HasName)); + // TODO GetNames -> libDecl.AddMethod("getNames", MethodImplementationType.ContractCall, VarKind.Storage_List, new MethodParameter[] {}).SetContract(contract).SetAlias(nameof(GovernanceContract.GetNames)); + // TODO GetValues -> libDecl.AddMethod("getValues", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "GovernancePair"), new [] { new MethodParameter("name", VarKind.String )}).SetContract(contract).SetAlias(nameof(GovernanceContract.GetValues)); + libDecl.AddMethod("hasValue", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.HasValue)); + libDecl.AddMethod("createValue", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("name", VarKind.String), new MethodParameter("initial", VarKind.Number), new MethodParameter("serializedConstraints", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(GovernanceContract.CreateValue)); + libDecl.AddMethod("getValue", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.GetValue)); + libDecl.AddMethod("setValue", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("name", VarKind.String), new MethodParameter("value", VarKind.Number) }).SetContract(contract).SetAlias(nameof(GovernanceContract.SetValue)); + break; + } + + case "Relay": + { + var contract = NativeContractKind.Relay.ToString().ToLower(); + libDecl.AddMethod("getBalance", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RelayContract.GetBalance)); + libDecl.AddMethod("getIndex", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RelayContract.GetIndex)); + libDecl.AddMethod("getTopUpAddress", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RelayContract.GetTopUpAddress)); + libDecl.AddMethod("openChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("publicKey", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(RelayContract.OpenChannel)); + libDecl.AddMethod("getKey", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RelayContract.GetKey)); + libDecl.AddMethod("topUpChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("count", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RelayContract.TopUpChannel)); + // TODO settleChannel -> libDecl.AddMethod("settleChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Struct) } ).SetContract(contract).SetAlias(nameof(RelayContract.SettleChannel)); + break; + } + + case "Mail": + { + var contract = NativeContractKind.Mail.ToString().ToLower(); + libDecl.AddMethod("pushMessage", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("archiveHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(MailContract.PushMessage)); + libDecl.AddMethod("domainExists", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.DomainExists)); + libDecl.AddMethod("registerDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.RegisterDomain)); + libDecl.AddMethod("unregisterDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.UnregisterDomain)); + libDecl.AddMethod("migrateDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("domainName", VarKind.String), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MailContract.MigrateDomain)); + // TODO Address[] GetDomainUsers(string domainName) -> libDecl.AddMethod("getDomainUsers", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "Address") , new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.GetDomainUsers)); + libDecl.AddMethod("joinDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.JoinDomain)); + libDecl.AddMethod("leaveDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.LeaveDomain)); + libDecl.AddMethod("getUserDomain", MethodImplementationType.ContractCall, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MailContract.GetUserDomain)); + break; + } + default: + throw new CompilerException("unknown library: " + name); + } + + return libDecl; + } + } +} diff --git a/Library/src/CodeGen/Module.cs b/Library/src/CodeGen/Module.cs index 62d26d5..ea67f06 100644 --- a/Library/src/CodeGen/Module.cs +++ b/Library/src/CodeGen/Module.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Phantasma.Business.Blockchain.Contracts; -using Phantasma.Business.Blockchain.Contracts.Native; using Phantasma.Business.Blockchain.Tokens; using Phantasma.Business.CodeGen.Assembler; using Phantasma.Business.VM; @@ -27,7 +22,7 @@ public enum ModuleKind } - public abstract class Module: Node + public abstract partial class Module : Node { public readonly string Name; @@ -112,749 +107,6 @@ public LibraryDeclaration FindLibrary(string name, bool required = true) return null; } - public void ImportLibrary(string name) - { - var lib = LoadLibrary(name, this.Scope, this.Kind); - Libraries[lib.Name] = lib; - } - - public static string[] AvailableLibraries = new[] { - "Call", "Runtime", "Math","Token", "NFT", "Organization", "Oracle", "Storage", "Contract", "Array", - "Leaderboard", "Market", "Account", "Crowdsale", "Stake", "Governance", "Relay", "Mail", - "Time", "Task", "UID", "Map", "List", "String", "Bytes", "Decimal", "Enum", "Address", "Module", FormatLibraryName }; - - public const string FormatLibraryName = "Format"; - - private static void GenerateCasts(LibraryDeclaration libDecl, VarKind baseType, VarKind[] types) - { - foreach (var kind in types) - { - if (kind == VarKind.Bytes) - { - throw new CompilerException("Don't try to generate toBytes, it will be automatically generated"); - } - - var castName = "to" + kind; - - if (Compiler.DebugMode) - { - Console.WriteLine($"Found cast: {baseType}.{castName}()"); - } - - libDecl.AddMethod(castName, MethodImplementationType.Custom, kind, new[] { new MethodParameter("target", baseType) }). - SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(kind); - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"CAST {reg} {reg} #{vmType}"); - return reg; - }); - } - } - - public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKind moduleKind) - { - if (name != name.UppercaseFirst() && name != "this") - { - throw new CompilerException("invalid library name: " + name); - } - - var libDecl = new LibraryDeclaration(scope, name); - - Builtins.FillLibrary(libDecl); - - VarKind libKind; - if (Enum.TryParse(name, out libKind) && libKind != VarKind.Bytes && libKind != VarKind.Method && libKind != VarKind.Task && libKind != VarKind.Array) - { - switch (libKind) - { - case VarKind.Decimal: - case VarKind.Struct: - case VarKind.Module: - libKind = VarKind.Any; - break; - } - - libDecl.AddMethod("toBytes", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", libKind) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.Bytes}"); - return reg; - }); - } - - switch (name) - { - case "Module": - libDecl.AddMethod("getScript", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module) }). - SetPreCallback((output, scope, expr) => - { - var reg = Compiler.Instance.AllocRegister(output, expr); - var module = expr.arguments[0].AsLiteral(); - var script = Base16.Encode(module.script); - output.AppendLine(expr, $"LOAD {reg} 0x{script}"); - return reg; - }); - - libDecl.AddMethod("getABI", MethodImplementationType.Custom, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Module) }). - SetPreCallback((output, scope, expr) => - { - var reg = Compiler.Instance.AllocRegister(output, expr); - var module = expr.arguments[0].AsLiteral(); - var abiBytes = module.abi.ToByteArray(); - var script = Base16.Encode(abiBytes); - output.AppendLine(expr, $"LOAD {reg} 0x{script}"); - return reg; - }); - - return libDecl; - - case "Struct": - libDecl.AddMethod("fromBytes", MethodImplementationType.Custom, VarKind.Struct, new[] { new MethodParameter("source", VarKind.Bytes) }); - return libDecl; - - case "String": - // NOTE those are builtins, so they are no longer declared here - //libDecl.AddMethod("toUpper", MethodImplementationType.LocalCall, VarKind.String, new[] { new MethodParameter("s", VarKind.String) }).SetAlias("string_upper"); - //libDecl.AddMethod("toLower", MethodImplementationType.LocalCall, VarKind.String, new[] { new MethodParameter("s", VarKind.String) }).SetAlias("string_lower"); - - libDecl.AddMethod("length", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.String) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"SIZE {reg} {reg}"); - return reg; - }); - - libDecl.AddMethod("substr", MethodImplementationType.Custom, VarKind.String, new[] { new MethodParameter("target", VarKind.String), new MethodParameter("index", VarKind.Number), new MethodParameter("length", VarKind.Number) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - var regB = expr.arguments[1].GenerateCode(output); - var regC = expr.arguments[2].GenerateCode(output); - output.AppendLine(expr, $"RANGE {reg} {reg} {regB} {regC}"); - Compiler.Instance.DeallocRegister(ref regB); - Compiler.Instance.DeallocRegister(ref regC); - return reg; - }); - - libDecl.AddMethod("toArray", MethodImplementationType.Custom, VarType.Find(VarKind.Array, VarType.Find(VarKind.Number)), new[] { new MethodParameter("target", VarKind.String) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.Struct}"); - return reg; - }); - - libDecl.AddMethod("fromArray", MethodImplementationType.Custom, VarKind.String, new[] { new MethodParameter("target", VarType.Find(VarKind.Array, VarType.Find(VarKind.Number))) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"CAST {reg} {reg} #{VMType.String}"); - return reg; - }); - - GenerateCasts(libDecl, VarKind.String, new VarKind[] { VarKind.Bool, VarKind.Number }); - - return libDecl; - - case "Bytes": - GenerateCasts(libDecl, VarKind.Bytes, new VarKind[] { VarKind.Bool, VarKind.String, VarKind.Number }); - return libDecl; - - case "Number": - GenerateCasts(libDecl, VarKind.Number, new VarKind[] { VarKind.String, VarKind.Timestamp, VarKind.Bool}); - return libDecl; - - case "Hash": - GenerateCasts(libDecl, VarKind.Hash, new VarKind[] { VarKind.String, VarKind.Number }); - return libDecl; - - case "Enum": - GenerateCasts(libDecl, VarKind.Enum, new VarKind[] { VarKind.String, VarKind.Number }); - - libDecl.AddMethod("isSet", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Enum), new MethodParameter("flag", VarKind.Enum) }). - SetPreCallback((output, scope, expr) => - { - var regA = expr.arguments[0].GenerateCode(output); - var regB = expr.arguments[1].GenerateCode(output); - - output.AppendLine(expr, $"AND {regA} {regB} {regA}"); - - Compiler.Instance.DeallocRegister(ref regB); - return regA; - }); - return libDecl; - - - case "Decimal": - libDecl.AddMethod("decimals", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.Any) }). - SetPreCallback((output, scope, expr) => - { - var reg = Compiler.Instance.AllocRegister(output, expr); - var arg = expr.arguments[0]; - var decType = (DecimalVarType)arg.ResultType; - output.AppendLine(expr, $"LOAD {reg} {decType.decimals}"); - return reg; - }); - - libDecl.AddMethod("convert", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("decimalPlaces", VarKind.Number), new MethodParameter("value", VarKind.Number) }). - SetPreCallback((output, scope, expr) => - { - var regA = expr.arguments[0].GenerateCode(output); - var regB = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {regB} 10"); - output.AppendLine(expr, $"POW {regB} {regA} {regA}"); - - Compiler.Instance.DeallocRegister(ref regB); - - regB = expr.arguments[1].GenerateCode(output); - output.AppendLine(expr, $"MUL {regB} {regA} {regA}"); - Compiler.Instance.DeallocRegister(ref regB); - - return regA; - }); - return libDecl; - - case "Array": - { - libDecl.AddMethod("length", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("target", VarKind.Any) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"COUNT {reg} {reg}"); - return reg; - }); - - return libDecl; - } - - - case "Address": - // TODO implementations of those - libDecl.AddMethod("isNull", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); - libDecl.AddMethod("isUser", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); - libDecl.AddMethod("isSystem", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); - libDecl.AddMethod("isInterop", MethodImplementationType.Custom, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }); - - GenerateCasts(libDecl, VarKind.Bytes, new VarKind[] { VarKind.String}); - - return libDecl; - } - - if (moduleKind == ModuleKind.Description) - { - switch (name) - { - case FormatLibraryName: - libDecl.AddMethod("decimals", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("value", VarKind.Number), new MethodParameter("symbol", VarKind.String) }); - libDecl.AddMethod("symbol", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("symbol", VarKind.String) }); - libDecl.AddMethod("account", MethodImplementationType.ExtCall, VarKind.String, new[] { new MethodParameter("address", VarKind.Address) }); - break; - - default: - throw new CompilerException("unknown library: " + name); - } - - return libDecl; - } - - switch (name) - { - case "Call": - libDecl.AddMethod("interop", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); - libDecl.AddMethod("contract", MethodImplementationType.ContractCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); - libDecl.AddMethod("method", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("method", VarKind.Method), new MethodParameter("...", VarKind.Any) }). - SetPreCallback((output, scope, expr) => - { - var contract = scope.Module as Contract; - if (contract == null) - { - throw new CompilerException("Cannot use Call.method outside of a contract"); - } - - var methodName = expr.arguments[0].AsLiteral(); - var method = contract.FindMethod(methodName); - if (method == null) - { - throw new CompilerException($"Cannot find local method '{methodName}' in contract '{contract.Name}'"); - } - - var label = method.GetEntryLabel(); - - // push the method arguments into the stack, in the proper order - for (int i = expr.arguments.Count - 1; i >= 1; i--) - { - var argReg = expr.arguments[i].GenerateCode(output); - output.AppendLine(expr, $"PUSH {argReg}"); - Compiler.Instance.DeallocRegister(ref argReg); - } - - var reg = Compiler.Instance.AllocRegister(output, expr, expr.NodeID); - output.AppendLine(expr, $"CALL @{label}"); - output.AppendLine(expr, $"POP {reg}"); - return reg; - }); - break; - - case "Chain": - { - libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("source", VarKind.Address), new MethodParameter("organization", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("parentName", VarKind.String) }).SetAlias("Nexus.CreateChain"); - break; - } - - case "Cryptography": - { - libDecl.AddMethod("AESDecrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESDecrypt"); - libDecl.AddMethod("AESEncrypt", MethodImplementationType.ExtCall, VarKind.Bytes, new[] { new MethodParameter("data", VarKind.Bytes), new MethodParameter("key", VarKind.Bytes) }).SetAlias("Runtime.AESEncrypt"); - break; - } - - case "Platform": - { - libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("source", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("externalAddress", VarKind.String), new MethodParameter("interopAddress", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Nexus.CreatePlatform"); - libDecl.AddMethod("setTokenHash", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("platform", VarKind.String), new MethodParameter("hash", VarKind.Bytes) }).SetAlias("Nexus.SetTokenPlatformHash"); - break; - } - - case "Runtime": - libDecl.AddMethod("expect", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("condition", VarKind.Bool), new MethodParameter("error", VarKind.String) }). - SetPreCallback((output, scope, expr) => - { - var reg = expr.arguments[0].GenerateCode(output); - output.AppendLine(expr, $"JMPIF {reg} @expect_{expr.NodeID}"); - - var reg2 = expr.arguments[1].GenerateCode(output); - output.AppendLine(expr, $"THROW {reg2}"); - - Compiler.Instance.DeallocRegister(ref reg2); - - output.AppendLine(expr, $"@expect_{expr.NodeID}: NOP"); - return reg; - }); - libDecl.AddMethod("log", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("message", VarKind.String) }); - libDecl.AddMethod("isWitness", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address) }); - libDecl.AddMethod("isTrigger", MethodImplementationType.ExtCall, VarKind.Bool, new MethodParameter[] { }); - libDecl.AddMethod("transactionHash", MethodImplementationType.ExtCall, VarKind.Hash, new MethodParameter[] { }); - libDecl.AddMethod("deployContract", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("contract", VarKind.Module)}).SetParameterCallback("contract", ConvertFieldToContractWithName); - libDecl.AddMethod("upgradeContract", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("contract", VarKind.Module)}).SetParameterCallback("contract", ConvertFieldToContractWithName); - libDecl.AddMethod("gasTarget", MethodImplementationType.ExtCall, VarKind.Address, new MethodParameter[] { }).SetAlias("Runtime.GasTarget"); - libDecl.AddMethod("context", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.Context"); - libDecl.AddMethod("previousContext", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { }).SetAlias("Runtime.PreviousContext"); - libDecl.AddMethod("version", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { }).SetAlias("Runtime.Version"); - libDecl.AddMethod("getGovernanceValue", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { new MethodParameter("tag", VarKind.String) }).SetAlias("Nexus.GetGovernanceValue"); - break; - - case "Task": - libDecl.AddMethod("start", MethodImplementationType.ExtCall, VarKind.Task, new MethodParameter[] { new MethodParameter("method", VarKind.Method), new MethodParameter("from", VarKind.Address), new MethodParameter("frequency", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TaskMode")), new MethodParameter("gasLimit", VarKind.Number) }).SetAlias("Task.Start"); - libDecl.AddMethod("stop", MethodImplementationType.ExtCall, VarKind.None, new MethodParameter[] { new MethodParameter("task", VarKind.Address) }).SetAlias("Task.Stop"); - libDecl.AddMethod("current", MethodImplementationType.ExtCall, VarKind.Task, new MethodParameter[] { }).SetAlias("Task.Current"); - break; - - case "Math": - libDecl.AddMethod("min", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("valA", VarKind.Number), new MethodParameter("valB", VarKind.Number) }). - SetPreCallback((output, scope, expr) => - { - var regA = expr.arguments[0].GenerateCode(output); - var regB = expr.arguments[1].GenerateCode(output); - output.AppendLine(expr, $"MIN {regA} {regA} {regB}"); - Compiler.Instance.DeallocRegister(ref regB); - return regA; - }); - - libDecl.AddMethod("max", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("valA", VarKind.Number), new MethodParameter("valB", VarKind.Number) }). - SetPreCallback((output, scope, expr) => - { - var regA = expr.arguments[0].GenerateCode(output); - var regB = expr.arguments[1].GenerateCode(output); - output.AppendLine(expr, $"MAX {regA} {regA} {regB}"); - Compiler.Instance.DeallocRegister(ref regB); - return regA; - }); - - // NOTE those are builtins, so they are no longer declared here - //libDecl.AddMethod("sqrt", MethodImplementationType.LocalCall, VarKind.Number, new[] { new MethodParameter("n", VarKind.Number) }).SetAlias("math_sqrt"); - break; - - case "Time": - GenerateCasts(libDecl, VarKind.Timestamp, new VarKind[] { VarKind.String, VarKind.Number }); - - libDecl.AddMethod("now", MethodImplementationType.ExtCall, VarKind.Timestamp, new MethodParameter[] { }).SetAlias("Runtime.Time"); - libDecl.AddMethod("unix", MethodImplementationType.Custom, VarKind.Timestamp, new[] { new MethodParameter("value", VarKind.Number) }).SetPostCallback((output, scope, method, reg) => - { - var nameExpr = method.arguments[0] as LiteralExpression; - if (nameExpr != null && nameExpr.type.Kind == VarKind.Number) - { - var timestamp = uint.Parse(nameExpr.value); - output.AppendLine(method, $"LOAD {reg} {timestamp}"); - method.CallNecessaryConstructors(output, VarKind.Timestamp, reg); - return reg; - } - else - { - throw new Exception("Expected literal number expression"); - } - }); - break; - - case "Account": - { - libDecl.AddMethod("getName", MethodImplementationType.ExtCall, VarKind.String, new MethodParameter[] { new MethodParameter("from", VarKind.Address) }).SetAlias("Account.Name"); - libDecl.AddMethod("getLastActivity", MethodImplementationType.ExtCall, VarKind.Timestamp, new MethodParameter[] { new MethodParameter("from", VarKind.Address) }).SetAlias("Account.LastActivity"); - var contract = NativeContractKind.Account.ToString().ToLower(); - libDecl.AddMethod("registerName", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(AccountContract.RegisterName)); - libDecl.AddMethod("unregisterName", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.UnregisterName)); - libDecl.AddMethod("registerScript", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("script", VarKind.Bytes), new MethodParameter("abiBytes", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(AccountContract.RegisterScript)); - libDecl.AddMethod("hasScript", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.HasScript)); - //libDecl.AddMethod("lookUpAddress", MethodImplementationType.ContractCall, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpAddress)); - libDecl.AddMethod("lookUpScript", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpScript)); - libDecl.AddMethod("lookUpABI", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpABI)); - libDecl.AddMethod("lookUpName", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(AccountContract.LookUpName)); - libDecl.AddMethod("migrate", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.Migrate)); - // TODO ContractMethod GetTriggerForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("trigger", VarKind.Struct) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); - // TODO IEnumerable GetTriggersForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("triggers", VarKind.Struct) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); - // TODO IEnumerable GetTriggersForABI -> libDecl.AddMethod("GetTriggerForABI", MethodImplementationType.ContractCall, VarKind.Struct, new[] { new MethodParameter("triggers", VarKind.Address) }).SetContract(contract).SetAlias(nameof(AccountContract.GetTriggersForABI)); - break; - } - - case "UID": - { - libDecl.AddMethod("generate", MethodImplementationType.ExtCall, VarKind.Number, new MethodParameter[] { }).SetAlias("Runtime.GenerateUID"); - break; - } - - case "Random": - // NOTE those are builtins, so they are no longer declared here - //libDecl.AddMethod("generate", MethodImplementationType.LocalCall, VarKind.Number, new MethodParameter[] { }).SetAlias("random_generate"); - //libDecl.AddMethod("seed", MethodImplementationType.LocalCall, VarKind.None, new[] { new MethodParameter("seed", VarKind.Number) }).SetAlias("random_seed"); - break; - - case "Token": - libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("decimals", VarKind.Number), new MethodParameter("flags", VarType.Find(VarKind.Enum, "TokenFlags")), new MethodParameter("script", VarKind.Bytes), new MethodParameter("abi", VarKind.Bytes) }).SetAlias("Nexus.CreateToken"); - libDecl.AddMethod("exists", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.TokenExists"); - libDecl.AddMethod("getDecimals", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenDecimals"); - libDecl.AddMethod("getFlags", MethodImplementationType.ExtCall, VarType.Find(VarKind.Enum, "TokenFlag"), new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenFlags"); - libDecl.AddMethod("transfer", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.TransferTokens"); - libDecl.AddMethod("transferAll", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.TransferBalance"); - libDecl.AddMethod("mint", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.MintTokens"); - libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("token ID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken"); - libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.BurnTokens"); - libDecl.AddMethod("swap", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("targetChain", VarKind.String), new MethodParameter("source", VarKind.Address), new MethodParameter("destination", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }).SetAlias("Runtime.SwapTokens"); - libDecl.AddMethod("getBalance", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetBalance"); - libDecl.AddMethod("isMinter", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.IsMinter"); - libDecl.AddMethod("getCurrentSupply", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("symbol", VarKind.String) }).SetAlias("Runtime.GetTokenSupply"); - libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableTokenSymbols"); - break; - - case "NFT": - libDecl.AddMethod("transfer", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.TransferToken"); - libDecl.AddMethod("mint", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("rom", VarKind.Any), new MethodParameter("ram", VarKind.Any), new MethodParameter("seriesID", VarKind.Any) }) - .SetParameterCallback("rom", ConvertFieldToBytes).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.MintToken"); - libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken"); - libDecl.AddMethod("readROM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenROM").SetPostCallback(ConvertGenericResult); - libDecl.AddMethod("readRAM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenRAM").SetPostCallback(ConvertGenericResult); - libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.BurnToken"); - libDecl.AddMethod("infuse", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) , new MethodParameter("infuseSymbol", VarKind.String), new MethodParameter("infuseValue", VarKind.Number) }).SetAlias("Runtime.InfuseToken"); - - libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableNFTSymbols"); - - libDecl.AddMethod("createSeries", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("seriesID", VarKind.Number), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TokenSeries")), new MethodParameter("nft", VarKind.Module) }). - SetAlias("Nexus.CreateTokenSeries").SetParameterCallback("nft", ConvertFieldToContractWithoutName); - - libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarType.Find(VarKind.Struct, "NFT"), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadToken") - .SetPreCallback((output, scope, expr) => - { - var nftStruct = VarType.Find(VarKind.Struct, "NFT") as StructVarType; - var reg = Compiler.Instance.AllocRegister(output, expr); - - var fields = '\"' + string.Join(',', nftStruct.decl.fields.Select(x => x.name)) + '\"'; - - output.AppendLine(expr, $"LOAD {reg} {fields} // field list"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback((output, scope, method, reg) => - { - output.AppendLine(method, $"UNPACK {reg} {reg}"); - return reg; - }); - break; - - case "Organization": - { - libDecl.AddMethod("create", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("id", VarKind.String), new MethodParameter("name", VarKind.String), new MethodParameter("script", VarKind.Bytes) }).SetAlias("Nexus.CreateOrganization"); - libDecl.AddMethod("addMember", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("target", VarKind.Address) }); - break; - } - - case "Oracle": - { - libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("url", VarKind.String) }); - libDecl.AddMethod("price", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String) }); - libDecl.AddMethod("quote", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("amount", VarKind.Number) }); - break; - } - - case "Storage": - { - libDecl.AddMethod("read", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("field", VarKind.String)}).SetAlias("Data.Get") - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback(ConvertGenericResult); - - libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("field", VarKind.String), new MethodParameter("value", VarKind.Any) }).SetAlias("Data.Set"); - libDecl.AddMethod("delete", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("field", VarKind.String) }).SetAlias("Data.Delete"); - var contract = NativeContractKind.Storage.ToString().ToLower(); - libDecl.AddMethod("calculateStorageSizeForStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StorageContract.CalculateStorageSizeForStake)); - libDecl.AddMethod("createFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("fileName", VarKind.String), new MethodParameter("fileSize", VarKind.Number), new MethodParameter("contentMerkle", VarKind.Bytes), new MethodParameter("encryptionContent", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.CreateFile)); - libDecl.AddMethod("hasFile", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("hash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.HasFile)); - libDecl.AddMethod("addFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("archiveHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.AddFile)); - libDecl.AddMethod("deleteFile", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("targetHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(StorageContract.DeleteFile)); - libDecl.AddMethod("hasPermission", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("external", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.HasPermission)); - libDecl.AddMethod("addPermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("externalAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.AddPermission)); - libDecl.AddMethod("deletePermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("externalAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.DeletePermission)); - //libDecl.AddMethod("migratePermission", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("oldAddr", VarKind.Address), new MethodParameter("newAddr", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.MigratePermission)); - //libDecl.AddMethod("migrate", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.Migrate)); - libDecl.AddMethod("getUsedSpace", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetUsedSpace)); - libDecl.AddMethod("getAvailableSpace", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetAvailableSpace)); - // TODO Hash[] GetFiles(Address from) -> libDecl.AddMethod("getFiles", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetFiles)); - libDecl.AddMethod("getUsedDataQuota", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StorageContract.GetUsedDataQuota)); - //libDecl.AddMethod("writeData", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("key", VarKind.Bytes), new MethodParameter("value", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.WriteData)); - //libDecl.AddMethod("deleteData", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("target", VarKind.Address), new MethodParameter("key", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(StorageContract.DeleteData)); - - break; - } - - case "Contract": - libDecl.AddMethod("call", MethodImplementationType.ContractCall, VarType.Generic(0), new[] { new MethodParameter("contract", VarKind.String), new MethodParameter("method", VarKind.String), new MethodParameter("...", VarKind.Any) }); - libDecl.AddMethod("exists", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("name", VarKind.String) }).SetAlias("Runtime.ContractExists"); - - libDecl.AddMethod("address", MethodImplementationType.Custom, VarKind.Address, new[] { new MethodParameter("name", VarKind.String) }).SetPostCallback((output, scope, method, reg) => - { - var nameExpr = method.arguments[0] as LiteralExpression; - if (nameExpr != null && nameExpr.type.Kind == VarKind.String) - { - var address = SmartContract.GetAddressFromContractName(nameExpr.value); - var hex = Base16.Encode(address.ToByteArray()); - output.AppendLine(method, $"LOAD {reg} 0x{hex}"); - return reg; - } - else - { - throw new Exception("Expected literal string expression"); - } - }); - break; - - case "Leaderboard": - { - var contract = NativeContractKind.Ranking.ToString().ToLower(); - libDecl.AddMethod("exists", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("boardName", VarKind.String)}).SetContract(contract).SetAlias(nameof(RankingContract.Exists)); - libDecl.AddMethod("create", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("boardName", VarKind.String), new MethodParameter("capacity", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.CreateLeaderboard)); - libDecl.AddMethod("getAddress", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.GetAddressByIndex)); - libDecl.AddMethod("getScoreByIndex", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.GetScoreByIndex)); - libDecl.AddMethod("getScoreByAddress", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RankingContract.GetScoreByAddress)); - libDecl.AddMethod("getSize", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("boardName", VarKind.String) }).SetContract(contract).SetAlias(nameof(RankingContract.GetSize)); - libDecl.AddMethod("insert", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("boardName", VarKind.String), new MethodParameter("score", VarKind.Number) }).SetContract(contract).SetAlias(nameof(RankingContract.InsertScore)); - libDecl.AddMethod("reset", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("boardName", VarKind.String) }).SetContract(contract).SetAlias(nameof(RankingContract.ResetLeaderboard)); - break; - } - - case "Market": - { - var contract = NativeContractKind.Market.ToString().ToLower(); - libDecl.AddMethod("sell", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endDate", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(MarketContract.SellToken)); - libDecl.AddMethod("buy", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.BuyToken)); - libDecl.AddMethod("cancel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.CancelSale)); - libDecl.AddMethod("hasAuction", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number) }).SetContract(contract).SetAlias(nameof(MarketContract.HasAuction)); - libDecl.AddMethod("bid", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("buyingFee", VarKind.Number), new MethodParameter("buyingFeeAddress", VarKind.Address)}).SetContract(contract).SetAlias(nameof(MarketContract.BidToken)); - // TODO GetAuction -> libDecl.AddMethod("getAuction", MethodImplementationType.ContractCall, VarType.Find(VarKind.Struct, "MarketAuction"), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number)}).SetContract(contract).SetAlias(nameof(MarketContract.GetAuction)); - // TODO GetAuctions -> libDecl.AddMethod("getAuctions", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_list, "MarketAuction"), new[] {} ).SetContract(contract).SetAlias(nameof(MarketContract.GetAuctions)); - libDecl.AddMethod("listToken", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endPrice", VarKind.Number), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("extensionPeriod", VarKind.Number), new MethodParameter("typeAuction", VarKind.Number), new MethodParameter("listingFee", VarKind.Number), new MethodParameter("listingFeeAddress", VarKind.Address)} ).SetContract(contract).SetAlias(nameof(MarketContract.ListToken)); - libDecl.AddMethod("editAuction", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("baseSymbol", VarKind.String), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("price", VarKind.Number), new MethodParameter("endPrice", VarKind.Number), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("extensionPeriod", VarKind.Number), } ).SetContract(contract).SetAlias(nameof(MarketContract.EditAuction)); - break; - } - - case "Array": - libDecl.AddMethod("get", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }) - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback(ConvertGenericResult); - - // TODO not implemented yet... for now use builtin TOMB array support, eg: local temp: array - libDecl.AddMethod("set", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }); - libDecl.AddMethod("remove", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }); - libDecl.AddMethod("clear", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any) }); - libDecl.AddMethod("count", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("array", VarKind.Any) }); - break; - - - case "Map": - libDecl.AddMethod("get", MethodImplementationType.ExtCall, VarType.Generic(1), new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead) - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback(ConvertGenericResult); - libDecl.AddMethod("set", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)), new MethodParameter("value", VarType.Generic(1)) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("remove", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("clear", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("map", VarKind.String) }).SetParameterCallback("map", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("count", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("map", VarKind.String) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead); - libDecl.AddMethod("has", MethodImplementationType.ExtCall, VarKind.Bool, new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead) - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }); - break; - - case "List": - libDecl.AddMethod("get", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetParameterCallback("list", ConvertFieldToStorageAccessRead) - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback(ConvertGenericResult); - - libDecl.AddMethod("add", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("value", VarType.Generic(0)) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("replace", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("removeAt", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String), new MethodParameter("index", VarKind.Number) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); - libDecl.AddMethod("count", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("list", VarKind.String) }).SetParameterCallback("list", ConvertFieldToStorageAccessRead); - libDecl.AddMethod("clear", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("list", VarKind.String) }).SetParameterCallback("list", ConvertFieldToStorageAccessWrite); - break; - - case "Crowdsale": - { - var contract = NativeContractKind.Sale.ToString().ToLower(); - // TODO GetSales -> libDecl.AddMethod("getSales", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "SaleInfo"), new MethodParameter[] { } ).SetContract(contract).SetAlias(nameof(SaleContract.GetSales)); - // TODO GetSale -> libDecl.AddMethod("getSale", MethodImplementationType.ContractCall, VarType.Find(VarKind.Struct, "SaleInfo"), new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSale)); - libDecl.AddMethod("isSeller", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.IsSeller)); - libDecl.AddMethod("isSaleActive", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.IsSaleActive)); - libDecl.AddMethod("create", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("name", VarKind.String), new MethodParameter("flags", VarKind.Struct), new MethodParameter("startDate", VarKind.Timestamp), new MethodParameter("endDate", VarKind.Timestamp), new MethodParameter("sellSymbol", VarKind.String), new MethodParameter("receiveSymbol", VarKind.String), new MethodParameter("price", VarKind.Number), new MethodParameter("globalSoftCap", VarKind.Number), new MethodParameter("globalHardCap", VarKind.Number), new MethodParameter("userSoftCap", VarKind.Number), new MethodParameter("userHardCap", VarKind.Number)}).SetContract(contract).SetAlias(nameof(SaleContract.CreateSale)); // TODO - // TODO getSaleParticipants -> libDecl.AddMethod("getSaleParticipants", MethodImplementationType.ContractCall, VarKind.Storage_List, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSaleParticipants)); - // TODO getSaleWhitelists -> libDecl.AddMethod("getSaleWhitelists", MethodImplementationType.ContractCall, VarKind.Storage_List, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSaleWhitelists)); - libDecl.AddMethod("isWhitelisted", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.IsWhitelisted)); - libDecl.AddMethod("addToWhitelist", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.AddToWhitelist)); - libDecl.AddMethod("removeFromWhitelist", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.RemoveFromWhitelist)); - libDecl.AddMethod("getPurchasedAmount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(SaleContract.GetPurchasedAmount)); - libDecl.AddMethod("getSoldAmount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.GetSoldAmount)); - libDecl.AddMethod("purchase", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("quoteSymbol", VarKind.String), new MethodParameter("quoteAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(SaleContract.Purchase)); - libDecl.AddMethod("closeSale", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("saleHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); - libDecl.AddMethod("getLatestSaleHash", MethodImplementationType.ContractCall, VarKind.Hash, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); - libDecl.AddMethod("editSalePrice", MethodImplementationType.ContractCall, VarKind.Hash, new[] { new MethodParameter("saleHash", VarKind.Hash), new MethodParameter("price", VarKind.Number) }).SetContract(contract).SetAlias(nameof(SaleContract.CloseSale)); - break; - } - - case "Stake": - { - var contract = NativeContractKind.Stake.ToString().ToLower(); - libDecl.AddMethod("getMasterThreshold", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterThreshold)); - libDecl.AddMethod("isMaster", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.IsMaster)); - libDecl.AddMethod("getMasterCount", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterCount)); - libDecl.AddMethod("getMasterAddresses", MethodImplementationType.ContractCall, VarKind.Number, new MethodParameter[] { }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterCount)); - libDecl.AddMethod("getClaimMasterCount", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("claimDate", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(StakeContract.GetClaimMasterCount)); - libDecl.AddMethod("getMasterClaimDate", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("claimDistance", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterClaimDate)); - libDecl.AddMethod("getMasterDate", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterDate)); - libDecl.AddMethod("getMasterClaimDateFromReference", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("claimDistance", VarKind.Number), new MethodParameter("referenceTime", VarKind.Timestamp) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterClaimDateFromReference)); - libDecl.AddMethod("getMasterRewards", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetMasterRewards)); - libDecl.AddMethod("masterClaim", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.MasterClaim)); - libDecl.AddMethod("stake", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.Stake)); - libDecl.AddMethod("unstake", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("unstakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.Unstake)); - libDecl.AddMethod("getTimeBeforeUnstake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetTimeBeforeUnstake)); - libDecl.AddMethod("getStakeTimestamp", MethodImplementationType.ContractCall, VarKind.Timestamp, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStakeTimestamp)); - libDecl.AddMethod("getUnclaimed", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetUnclaimed)); - libDecl.AddMethod("claim", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("stakeAddress", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.Claim)); - libDecl.AddMethod("getStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStake)); - libDecl.AddMethod("getStorageStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetStorageStake)); - libDecl.AddMethod("fuelToStake", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("fuelAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.FuelToStake)); - libDecl.AddMethod("stakeToFuel", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("stakeAmount", VarKind.Number) }).SetContract(contract).SetAlias(nameof(StakeContract.StakeToFuel)); - libDecl.AddMethod("getAddressVotingPower", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("address", VarKind.Address) }).SetContract(contract).SetAlias(nameof(StakeContract.GetAddressVotingPower)); - break; - } - - case "Governance": - { - var contract = NativeContractKind.Governance.ToString().ToLower(); - libDecl.AddMethod("hasName", MethodImplementationType.ContractCall, VarKind.Bool, new [] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.HasName)); - // TODO GetNames -> libDecl.AddMethod("getNames", MethodImplementationType.ContractCall, VarKind.Storage_List, new MethodParameter[] {}).SetContract(contract).SetAlias(nameof(GovernanceContract.GetNames)); - // TODO GetValues -> libDecl.AddMethod("getValues", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "GovernancePair"), new [] { new MethodParameter("name", VarKind.String )}).SetContract(contract).SetAlias(nameof(GovernanceContract.GetValues)); - libDecl.AddMethod("hasValue", MethodImplementationType.ContractCall, VarKind.Bool, new [] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.HasValue)); - libDecl.AddMethod("createValue", MethodImplementationType.ContractCall, VarKind.None, new [] { new MethodParameter("name", VarKind.String), new MethodParameter("initial", VarKind.Number), new MethodParameter("serializedConstraints", VarKind.Bytes) }).SetContract(contract).SetAlias(nameof(GovernanceContract.CreateValue)); - libDecl.AddMethod("getValue", MethodImplementationType.ContractCall, VarKind.Number, new [] { new MethodParameter("name", VarKind.String) }).SetContract(contract).SetAlias(nameof(GovernanceContract.GetValue)); - libDecl.AddMethod("setValue", MethodImplementationType.ContractCall, VarKind.None, new [] { new MethodParameter("name", VarKind.String), new MethodParameter("value", VarKind.Number) }).SetContract(contract).SetAlias(nameof(GovernanceContract.SetValue)); - break; - } - - case "Relay": - { - var contract = NativeContractKind.Relay.ToString().ToLower(); - libDecl.AddMethod("getBalance", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address) } ).SetContract(contract).SetAlias(nameof(RelayContract.GetBalance)); - libDecl.AddMethod("getIndex", MethodImplementationType.ContractCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address) } ).SetContract(contract).SetAlias(nameof(RelayContract.GetIndex)); - libDecl.AddMethod("getTopUpAddress", MethodImplementationType.ContractCall, VarKind.Address, new[] { new MethodParameter("from", VarKind.Address) } ).SetContract(contract).SetAlias(nameof(RelayContract.GetTopUpAddress)); - libDecl.AddMethod("openChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("publicKey", VarKind.Bytes) } ).SetContract(contract).SetAlias(nameof(RelayContract.OpenChannel)); - libDecl.AddMethod("getKey", MethodImplementationType.ContractCall, VarKind.Bytes, new[] { new MethodParameter("from", VarKind.Address) }).SetContract(contract).SetAlias(nameof(RelayContract.GetKey)); - libDecl.AddMethod("topUpChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("count", VarKind.Number) } ).SetContract(contract).SetAlias(nameof(RelayContract.TopUpChannel)); - // TODO settleChannel -> libDecl.AddMethod("settleChannel", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Struct) } ).SetContract(contract).SetAlias(nameof(RelayContract.SettleChannel)); - break; - } - - case "Mail": - { - var contract = NativeContractKind.Mail.ToString().ToLower(); - libDecl.AddMethod("pushMessage", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("target", VarKind.Address), new MethodParameter("archiveHash", VarKind.Hash) }).SetContract(contract).SetAlias(nameof(MailContract.PushMessage)); - libDecl.AddMethod("domainExists", MethodImplementationType.ContractCall, VarKind.Bool, new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.DomainExists)); - libDecl.AddMethod("registerDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.RegisterDomain)); - libDecl.AddMethod("unregisterDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.UnregisterDomain)); - libDecl.AddMethod("migrateDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("domainName", VarKind.String), new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MailContract.MigrateDomain)); - // TODO Address[] GetDomainUsers(string domainName) -> libDecl.AddMethod("getDomainUsers", MethodImplementationType.ContractCall, VarType.Find(VarKind.Storage_List, "Address") , new[] { new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.GetDomainUsers)); - libDecl.AddMethod("joinDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.JoinDomain)); - libDecl.AddMethod("leaveDomain", MethodImplementationType.ContractCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("domainName", VarKind.String) }).SetContract(contract).SetAlias(nameof(MailContract.LeaveDomain)); - libDecl.AddMethod("getUserDomain", MethodImplementationType.ContractCall, VarKind.String, new[] { new MethodParameter("target", VarKind.Address) }).SetContract(contract).SetAlias(nameof(MailContract.GetUserDomain)); - break; - } - default: - throw new CompilerException("unknown library: " + name); - } - - return libDecl; - } - private static Register ConvertFieldToStorageAccessRead(CodeGenerator output, Scope scope, Expression expression) { return ConvertFieldToStorageAccess(output, scope, expression, true); From beee394b654fc027b82b305c4149ebe18da1955d Mon Sep 17 00:00:00 2001 From: Sergio Flores Date: Sat, 5 Aug 2023 14:32:43 +0100 Subject: [PATCH 2/4] Support for latest Phantasma packages --- Compiler/TombCompiler.csproj | 2 + .../src/AST/Declarations/EventDeclaration.cs | 9 ++++ .../AST/Declarations/LibraryDeclaration.cs | 1 + .../src/AST/Declarations/MethodDeclaration.cs | 3 ++ .../src/AST/Expressions/BinaryExpression.cs | 1 + .../src/AST/Expressions/MacroExpression.cs | 1 + Library/src/AST/MethodInterface.cs | 1 + Library/src/CodeGen/Contract.cs | 3 ++ Library/src/CodeGen/Libraries.cs | 48 ++++++++++--------- Library/src/CodeGen/Module.cs | 5 +- Library/src/CodeGen/NFT.cs | 3 ++ Library/src/CodeGen/Script.cs | 1 + Library/src/Compiler.cs | 6 +-- Library/src/Compilers/SolidityCompiler.cs | 2 + Library/src/Compilers/TombLangCompiler.cs | 14 +++++- Library/src/Lexers/SolidityLexer.cs | 1 + Library/src/Lexers/TombLangLexer.cs | 1 + Library/src/TOMBLib.csproj | 5 +- Library/tests/Contracts/AddressTests.cs | 3 ++ Library/tests/Contracts/ArrayTests.cs | 3 ++ Library/tests/Contracts/BooleanTests.cs | 3 ++ Library/tests/Contracts/ConstantsTests.cs | 1 + Library/tests/Contracts/DecimalTests.cs | 3 ++ Library/tests/Contracts/EnumsTests.cs | 3 ++ Library/tests/Contracts/ForTests.cs | 1 + Library/tests/Contracts/IfTests.cs | 2 + Library/tests/Contracts/MethodTests.cs | 2 + Library/tests/Contracts/NumberTests.cs | 3 ++ Library/tests/Contracts/PropertiesTests.cs | 3 ++ Library/tests/Contracts/ReturnTests.cs | 1 + Library/tests/Contracts/StringTests.cs | 3 ++ Library/tests/Contracts/SwitchTest.cs | 2 + Library/tests/Contracts/VariableTests.cs | 2 + Library/tests/GeneralTests.cs | 1 + Library/tests/TOMBLib.Tests.csproj | 2 + Library/tests/TestVM.cs | 24 ++++++++-- 36 files changed, 132 insertions(+), 37 deletions(-) diff --git a/Compiler/TombCompiler.csproj b/Compiler/TombCompiler.csproj index f51ecec..5f35738 100644 --- a/Compiler/TombCompiler.csproj +++ b/Compiler/TombCompiler.csproj @@ -12,6 +12,8 @@ + + diff --git a/Library/src/AST/Declarations/EventDeclaration.cs b/Library/src/AST/Declarations/EventDeclaration.cs index e4b374e..881956a 100644 --- a/Library/src/AST/Declarations/EventDeclaration.cs +++ b/Library/src/AST/Declarations/EventDeclaration.cs @@ -9,6 +9,15 @@ using Phantasma.Business.Blockchain; using Phantasma.Business.CodeGen.Assembler; using Phantasma.Business.Blockchain.VM; +using Phantasma.Core.Domain.VM; +using Phantasma.Core.Domain.Interfaces; +using Phantasma.Core.Domain.Token.Structs; +using Phantasma.Core.Cryptography.Structs; +using Phantasma.Core.Domain.Token.Enums; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.VM.Enums; +using Phantasma.Core.Domain.Events.Structs; +using Phantasma.Core.Domain.Execution.Enums; namespace Phantasma.Tomb.AST.Declarations { diff --git a/Library/src/AST/Declarations/LibraryDeclaration.cs b/Library/src/AST/Declarations/LibraryDeclaration.cs index 7e20f1d..e86b84b 100644 --- a/Library/src/AST/Declarations/LibraryDeclaration.cs +++ b/Library/src/AST/Declarations/LibraryDeclaration.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Validation; using Phantasma.Tomb.CodeGen; namespace Phantasma.Tomb.AST.Declarations diff --git a/Library/src/AST/Declarations/MethodDeclaration.cs b/Library/src/AST/Declarations/MethodDeclaration.cs index 6912ad5..68f0a8d 100644 --- a/Library/src/AST/Declarations/MethodDeclaration.cs +++ b/Library/src/AST/Declarations/MethodDeclaration.cs @@ -1,4 +1,7 @@ using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Contract.Structs; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Tomb.AST.Statements; using Phantasma.Tomb.CodeGen; diff --git a/Library/src/AST/Expressions/BinaryExpression.cs b/Library/src/AST/Expressions/BinaryExpression.cs index f60d0dd..72be1b7 100644 --- a/Library/src/AST/Expressions/BinaryExpression.cs +++ b/Library/src/AST/Expressions/BinaryExpression.cs @@ -1,4 +1,5 @@ using Phantasma.Core.Domain; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Tomb.CodeGen; using System; diff --git a/Library/src/AST/Expressions/MacroExpression.cs b/Library/src/AST/Expressions/MacroExpression.cs index 445ce63..6e2b8e3 100644 --- a/Library/src/AST/Expressions/MacroExpression.cs +++ b/Library/src/AST/Expressions/MacroExpression.cs @@ -1,4 +1,5 @@ using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; using Phantasma.Core.Numerics; using Phantasma.Tomb.CodeGen; diff --git a/Library/src/AST/MethodInterface.cs b/Library/src/AST/MethodInterface.cs index ed5cd15..1785e15 100644 --- a/Library/src/AST/MethodInterface.cs +++ b/Library/src/AST/MethodInterface.cs @@ -4,6 +4,7 @@ using Phantasma.Tomb.AST.Expressions; using Phantasma.Tomb.AST.Declarations; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.VM.Enums; namespace Phantasma.Tomb.AST { diff --git a/Library/src/CodeGen/Contract.cs b/Library/src/CodeGen/Contract.cs index b37f9b8..e115bea 100644 --- a/Library/src/CodeGen/Contract.cs +++ b/Library/src/CodeGen/Contract.cs @@ -1,5 +1,8 @@ using Phantasma.Business.VM; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Validation; +using Phantasma.Core.Domain.VM.Structs; using Phantasma.Tomb.AST; using Phantasma.Tomb.AST.Declarations; using Phantasma.Tomb.AST.Expressions; diff --git a/Library/src/CodeGen/Libraries.cs b/Library/src/CodeGen/Libraries.cs index 204aee3..88a6832 100644 --- a/Library/src/CodeGen/Libraries.cs +++ b/Library/src/CodeGen/Libraries.cs @@ -1,5 +1,7 @@ using Phantasma.Business.Blockchain.Contracts.Native; -using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Contract.Enums; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Core.Numerics; using Phantasma.Tomb.AST; using Phantasma.Tomb.AST.Declarations; @@ -225,6 +227,24 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin return reg; }); + libDecl.AddMethod("get", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }) + .SetPreCallback((output, scope, expr) => + { + var vmType = MethodInterface.ConvertType(expr.method.ReturnType); + var reg = Compiler.Instance.AllocRegister(output, expr); + + output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); + output.AppendLine(expr, $"PUSH {reg}"); + + return reg; + }) + .SetPostCallback(ConvertGenericResult); + + // TODO not implemented yet... for now use builtin TOMB array support, eg: local temp: array + libDecl.AddMethod("set", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }); + libDecl.AddMethod("remove", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }); + libDecl.AddMethod("clear", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any) }); + return libDecl; } @@ -455,6 +475,10 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.BurnToken"); libDecl.AddMethod("infuse", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number), new MethodParameter("infuseSymbol", VarKind.String), new MethodParameter("infuseValue", VarKind.Number) }).SetAlias("Runtime.InfuseToken"); + var nftArray = VarType.Find(VarKind.Array, VarType.Find(VarKind.Struct, "NFT")); + + libDecl.AddMethod("getInfusions", MethodImplementationType.ExtCall, nftArray, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("token_id", VarKind.Number)}).SetAlias("Runtime.ReadInfusions"); + libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableNFTSymbols"); libDecl.AddMethod("createSeries", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("seriesID", VarKind.Number), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TokenSeries")), new MethodParameter("nft", VarKind.Module) }). @@ -583,28 +607,6 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin break; } - case "Array": - libDecl.AddMethod("get", MethodImplementationType.Custom, VarType.Generic(0), new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }) - .SetPreCallback((output, scope, expr) => - { - var vmType = MethodInterface.ConvertType(expr.method.ReturnType); - var reg = Compiler.Instance.AllocRegister(output, expr); - - output.AppendLine(expr, $"LOAD {reg} {(int)vmType} // field type"); - output.AppendLine(expr, $"PUSH {reg}"); - - return reg; - }) - .SetPostCallback(ConvertGenericResult); - - // TODO not implemented yet... for now use builtin TOMB array support, eg: local temp: array - libDecl.AddMethod("set", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number), new MethodParameter("value", VarType.Generic(0)) }); - libDecl.AddMethod("remove", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any), new MethodParameter("index", VarKind.Number) }); - libDecl.AddMethod("clear", MethodImplementationType.Custom, VarKind.None, new[] { new MethodParameter("array", VarKind.Any) }); - libDecl.AddMethod("count", MethodImplementationType.Custom, VarKind.Number, new[] { new MethodParameter("array", VarKind.Any) }); - break; - - case "Map": libDecl.AddMethod("get", MethodImplementationType.ExtCall, VarType.Generic(1), new[] { new MethodParameter("map", VarKind.String), new MethodParameter("key", VarType.Generic(0)) }).SetParameterCallback("map", ConvertFieldToStorageAccessRead) .SetPreCallback((output, scope, expr) => diff --git a/Library/src/CodeGen/Module.cs b/Library/src/CodeGen/Module.cs index ea67f06..4c74965 100644 --- a/Library/src/CodeGen/Module.cs +++ b/Library/src/CodeGen/Module.cs @@ -1,7 +1,8 @@ using Phantasma.Business.Blockchain.Tokens; using Phantasma.Business.CodeGen.Assembler; -using Phantasma.Business.VM; -using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.VM.Enums; +using Phantasma.Core.Domain.VM.Structs; using Phantasma.Core.Numerics; using Phantasma.Tomb.AST; using Phantasma.Tomb.AST.Declarations; diff --git a/Library/src/CodeGen/NFT.cs b/Library/src/CodeGen/NFT.cs index 4c86384..8542c42 100644 --- a/Library/src/CodeGen/NFT.cs +++ b/Library/src/CodeGen/NFT.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; using Phantasma.Business.Blockchain.Tokens; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Contract.Structs; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Tomb.AST; using Phantasma.Tomb.AST.Declarations; diff --git a/Library/src/CodeGen/Script.cs b/Library/src/CodeGen/Script.cs index 8bc1715..19b6e54 100644 --- a/Library/src/CodeGen/Script.cs +++ b/Library/src/CodeGen/Script.cs @@ -3,6 +3,7 @@ using Phantasma.Tomb.AST.Statements; using Phantasma.Tomb.AST.Declarations; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; namespace Phantasma.Tomb.CodeGen { diff --git a/Library/src/Compiler.cs b/Library/src/Compiler.cs index 3526089..0a615d9 100644 --- a/Library/src/Compiler.cs +++ b/Library/src/Compiler.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Metadata; -using Phantasma.Business.VM; +using Phantasma.Business.VM; using Phantasma.Core.Domain; using Phantasma.Tomb.AST; using Phantasma.Tomb.AST.Declarations; diff --git a/Library/src/Compilers/SolidityCompiler.cs b/Library/src/Compilers/SolidityCompiler.cs index 10fa1a4..b27b91d 100644 --- a/Library/src/Compilers/SolidityCompiler.cs +++ b/Library/src/Compilers/SolidityCompiler.cs @@ -11,6 +11,8 @@ using Phantasma.Tomb.Lexers; using Phantasma.Tomb.AST.Expressions; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Validation; namespace Phantasma.Tomb.Compilers { diff --git a/Library/src/Compilers/TombLangCompiler.cs b/Library/src/Compilers/TombLangCompiler.cs index 09578f4..ca15116 100644 --- a/Library/src/Compilers/TombLangCompiler.cs +++ b/Library/src/Compilers/TombLangCompiler.cs @@ -10,6 +10,12 @@ using Phantasma.Tomb.Lexers; using Phantasma.Core.Domain; using Phantasma.Core.Numerics; +using Phantasma.Core.Domain.Triggers.Enums; +using Phantasma.Core.Domain.Token.Enums; +using Phantasma.Core.Domain.Tasks.Enum; +using Phantasma.Core.Domain.Validation; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Events.Structs; namespace Phantasma.Tomb.Compilers { @@ -47,6 +53,12 @@ private void InitStructs() new StructField("seriesID", VarKind.Number), new StructField("mintID", VarKind.Number), }); + + CreateStruct("Infusion", new[] + { + new StructField("Symbol", VarKind.String), + new StructField("Value", VarKind.Number) + }); } @@ -694,7 +706,7 @@ private void ParseModule(Module module) { case ModuleKind.Account: case ModuleKind.Contract: - validTriggerNames = Enum.GetNames(typeof(AccountTrigger)).ToArray(); + validTriggerNames = Enum.GetNames(typeof(ContractTrigger)).ToArray(); break; case ModuleKind.Token: diff --git a/Library/src/Lexers/SolidityLexer.cs b/Library/src/Lexers/SolidityLexer.cs index f120898..97abb5a 100644 --- a/Library/src/Lexers/SolidityLexer.cs +++ b/Library/src/Lexers/SolidityLexer.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Text; using Phantasma.Core.Cryptography; +using Phantasma.Core.Cryptography.Structs; using Phantasma.Core.Numerics; using Phantasma.Tomb.AST; diff --git a/Library/src/Lexers/TombLangLexer.cs b/Library/src/Lexers/TombLangLexer.cs index e8be2de..f559cbd 100644 --- a/Library/src/Lexers/TombLangLexer.cs +++ b/Library/src/Lexers/TombLangLexer.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Text; using Phantasma.Core.Cryptography; +using Phantasma.Core.Cryptography.Structs; using Phantasma.Core.Numerics; using Phantasma.Tomb.AST; diff --git a/Library/src/TOMBLib.csproj b/Library/src/TOMBLib.csproj index 666d8ce..f23f5e7 100644 --- a/Library/src/TOMBLib.csproj +++ b/Library/src/TOMBLib.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -21,7 +21,8 @@ - + + diff --git a/Library/tests/Contracts/AddressTests.cs b/Library/tests/Contracts/AddressTests.cs index b837c1e..88508ad 100644 --- a/Library/tests/Contracts/AddressTests.cs +++ b/Library/tests/Contracts/AddressTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/ArrayTests.cs b/Library/tests/Contracts/ArrayTests.cs index 7b6c80a..129a8f7 100644 --- a/Library/tests/Contracts/ArrayTests.cs +++ b/Library/tests/Contracts/ArrayTests.cs @@ -2,6 +2,9 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/BooleanTests.cs b/Library/tests/Contracts/BooleanTests.cs index a9b0d7f..4667268 100644 --- a/Library/tests/Contracts/BooleanTests.cs +++ b/Library/tests/Contracts/BooleanTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/ConstantsTests.cs b/Library/tests/Contracts/ConstantsTests.cs index 0b4a242..c7605dc 100644 --- a/Library/tests/Contracts/ConstantsTests.cs +++ b/Library/tests/Contracts/ConstantsTests.cs @@ -2,6 +2,7 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/DecimalTests.cs b/Library/tests/Contracts/DecimalTests.cs index 5f5c8df..988a412 100644 --- a/Library/tests/Contracts/DecimalTests.cs +++ b/Library/tests/Contracts/DecimalTests.cs @@ -4,6 +4,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Numerics; using Phantasma.Core.Utils; using Phantasma.Tomb; diff --git a/Library/tests/Contracts/EnumsTests.cs b/Library/tests/Contracts/EnumsTests.cs index bfa253f..b2d1f7a 100644 --- a/Library/tests/Contracts/EnumsTests.cs +++ b/Library/tests/Contracts/EnumsTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/ForTests.cs b/Library/tests/Contracts/ForTests.cs index b4d8d8e..91611e0 100644 --- a/Library/tests/Contracts/ForTests.cs +++ b/Library/tests/Contracts/ForTests.cs @@ -2,6 +2,7 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/IfTests.cs b/Library/tests/Contracts/IfTests.cs index 2da52a2..c6501e3 100644 --- a/Library/tests/Contracts/IfTests.cs +++ b/Library/tests/Contracts/IfTests.cs @@ -2,6 +2,8 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/MethodTests.cs b/Library/tests/Contracts/MethodTests.cs index 4ecd909..197daf9 100644 --- a/Library/tests/Contracts/MethodTests.cs +++ b/Library/tests/Contracts/MethodTests.cs @@ -3,6 +3,8 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/NumberTests.cs b/Library/tests/Contracts/NumberTests.cs index 7f77b0b..7298c3f 100644 --- a/Library/tests/Contracts/NumberTests.cs +++ b/Library/tests/Contracts/NumberTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/PropertiesTests.cs b/Library/tests/Contracts/PropertiesTests.cs index 47ed152..c876214 100644 --- a/Library/tests/Contracts/PropertiesTests.cs +++ b/Library/tests/Contracts/PropertiesTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/ReturnTests.cs b/Library/tests/Contracts/ReturnTests.cs index 0d0f512..da03393 100644 --- a/Library/tests/Contracts/ReturnTests.cs +++ b/Library/tests/Contracts/ReturnTests.cs @@ -2,6 +2,7 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; using Phantasma.Core.Utils; using Phantasma.Tomb; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/StringTests.cs b/Library/tests/Contracts/StringTests.cs index 0a5b3f2..2d0ee45 100644 --- a/Library/tests/Contracts/StringTests.cs +++ b/Library/tests/Contracts/StringTests.cs @@ -3,6 +3,9 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/SwitchTest.cs b/Library/tests/Contracts/SwitchTest.cs index cc119d3..9cf7ca1 100644 --- a/Library/tests/Contracts/SwitchTest.cs +++ b/Library/tests/Contracts/SwitchTest.cs @@ -2,6 +2,8 @@ using System.Linq; using NUnit.Framework; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/Contracts/VariableTests.cs b/Library/tests/Contracts/VariableTests.cs index ca1bbc1..7fe1984 100644 --- a/Library/tests/Contracts/VariableTests.cs +++ b/Library/tests/Contracts/VariableTests.cs @@ -3,6 +3,8 @@ using NUnit.Framework; using Phantasma.Core.Cryptography; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.VM.Enums; using Phantasma.Core.Utils; using Phantasma.Tomb.Compilers; diff --git a/Library/tests/GeneralTests.cs b/Library/tests/GeneralTests.cs index e0e15a3..4b3ceaa 100644 --- a/Library/tests/GeneralTests.cs +++ b/Library/tests/GeneralTests.cs @@ -7,6 +7,7 @@ using Phantasma.Core.Utils; using Phantasma.Tomb; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; namespace TOMBLib.Tests { diff --git a/Library/tests/TOMBLib.Tests.csproj b/Library/tests/TOMBLib.Tests.csproj index c5fccb1..4d8052c 100644 --- a/Library/tests/TOMBLib.Tests.csproj +++ b/Library/tests/TOMBLib.Tests.csproj @@ -19,6 +19,8 @@ + + diff --git a/Library/tests/TestVM.cs b/Library/tests/TestVM.cs index 207ce77..86cd6bd 100644 --- a/Library/tests/TestVM.cs +++ b/Library/tests/TestVM.cs @@ -1,13 +1,18 @@ -using System; -using System.Collections.Generic; using Phantasma.Business.Blockchain.VM; using Phantasma.Business.CodeGen.Assembler; using Phantasma.Business.VM; using Phantasma.Business.VM.Utils; -using Phantasma.Core.Cryptography; +using Phantasma.Core.Cryptography.Structs; using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Contract; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.Serializer; +using Phantasma.Core.Domain.VM; +using Phantasma.Core.Domain.VM.Enums; +using Phantasma.Core.Numerics; using Phantasma.Tomb.CodeGen; -using ExecutionContext = Phantasma.Core.Domain.ExecutionContext; + +using ExecutionContext = Phantasma.Core.Domain.Execution.ExecutionContext; namespace TOMBLib.Tests; @@ -40,6 +45,7 @@ public TestVM(Module module, Dictionary storage, ContractMethod RegisterMethod("Runtime.Version", Runtime_Version); RegisterMethod("Runtime.TransactionHash", Runtime_TransactionHash); RegisterMethod("Runtime.Context", Runtime_Context); + RegisterMethod("Runtime.ReadInfusions", Runtime_ReadInfusions); RegisterMethod("Runtime.GetAvailableTokenSymbols", Runtime_GetAvailableTokenSymbols); @@ -186,6 +192,16 @@ private ExecutionState Runtime_TransactionHash(VirtualMachine vm) return ExecutionState.Running; } + private ExecutionState Runtime_ReadInfusions(VirtualMachine vm) + { + var symbol = vm.PopString("symbol"); + var id = vm.PopNumber("token_id"); + + var val = Serialization.Unserialize(Base16.Decode("0102030100081E0102040653796D626F6C0404534F554C040556616C7565030500CA9A3B0003020100083A0102040653796D626F6C04044E434F4C040556616C756503219905474F01A1DC34E8C3DB6657A297B6A3F69EE81E7BEC97DF171F79231AAD1C00")); + this.Stack.Push(val); + + return ExecutionState.Running; + } private ExecutionState Runtime_Context(VirtualMachine vm) { From d786f2c7dae4f1d62f1abaff81bc811263bfe66a Mon Sep 17 00:00:00 2001 From: Sergio Flores Date: Sat, 5 Aug 2023 15:59:38 +0100 Subject: [PATCH 3/4] Added support for getInfusions() --- .../AST/Expressions/ArrayElementExpression.cs | 10 +- Library/src/CodeGen/Libraries.cs | 4 +- Library/src/Compiler.cs | 2 +- Library/tests/Contracts/NFTTests.cs | 1549 +++++++++-------- Library/tests/TestVM.cs | 25 +- README.md | 46 +- 6 files changed, 909 insertions(+), 727 deletions(-) diff --git a/Library/src/AST/Expressions/ArrayElementExpression.cs b/Library/src/AST/Expressions/ArrayElementExpression.cs index 86f8244..816ddb4 100644 --- a/Library/src/AST/Expressions/ArrayElementExpression.cs +++ b/Library/src/AST/Expressions/ArrayElementExpression.cs @@ -31,7 +31,15 @@ public override Register GenerateCode(CodeGenerator output) var dstReg = Compiler.Instance.AllocRegister(output, this); var idxReg = indexExpression.GenerateCode(output); - output.AppendLine(this, $"GET {decl.Register} {dstReg} {idxReg}"); + var reg = decl.Register; + output.AppendLine(this, $"GET {reg} {dstReg} {idxReg}"); + + var arrayType = decl.Type as ArrayVarType; + if (arrayType == null) + { + throw new CompilerException(this, $"expected array type:" + decl.Name); + } + this.CallNecessaryConstructors(output, arrayType.elementType, decl.Register); Compiler.Instance.DeallocRegister(ref idxReg); diff --git a/Library/src/CodeGen/Libraries.cs b/Library/src/CodeGen/Libraries.cs index 88a6832..36733e9 100644 --- a/Library/src/CodeGen/Libraries.cs +++ b/Library/src/CodeGen/Libraries.cs @@ -476,9 +476,11 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin libDecl.AddMethod("infuse", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number), new MethodParameter("infuseSymbol", VarKind.String), new MethodParameter("infuseValue", VarKind.Number) }).SetAlias("Runtime.InfuseToken"); var nftArray = VarType.Find(VarKind.Array, VarType.Find(VarKind.Struct, "NFT")); - libDecl.AddMethod("getInfusions", MethodImplementationType.ExtCall, nftArray, new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("token_id", VarKind.Number)}).SetAlias("Runtime.ReadInfusions"); + var numberArray = VarType.Find(VarKind.Array, VarType.Find(VarKind.Number)); + libDecl.AddMethod("getOwnerships", MethodImplementationType.ExtCall, numberArray, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String)}).SetAlias("Runtime.GetOwnerships"); + libDecl.AddMethod("availableSymbols", MethodImplementationType.ExtCall, VarType.FindArray(VarKind.String), new MethodParameter[0] { }).SetAlias("Runtime.GetAvailableNFTSymbols"); libDecl.AddMethod("createSeries", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("seriesID", VarKind.Number), new MethodParameter("maxSupply", VarKind.Number), new MethodParameter("mode", VarType.Find(VarKind.Enum, "TokenSeries")), new MethodParameter("nft", VarKind.Module) }). diff --git a/Library/src/Compiler.cs b/Library/src/Compiler.cs index 0a615d9..7e2b446 100644 --- a/Library/src/Compiler.cs +++ b/Library/src/Compiler.cs @@ -534,7 +534,7 @@ private Expression ParseExpressionFromToken(LexerToken first, Scope scope) } } - var indexExpression = ParseArrayIndexingExpression(scope, tmp, arrayType.elementType); + var indexExpression = ParseArrayIndexingExpression(scope, tmp, VarType.Find(VarKind.Number)); return new ArrayElementExpression(scope, arrayVar, indexExpression); } diff --git a/Library/tests/Contracts/NFTTests.cs b/Library/tests/Contracts/NFTTests.cs index 9cff2f0..9d2c9cf 100644 --- a/Library/tests/Contracts/NFTTests.cs +++ b/Library/tests/Contracts/NFTTests.cs @@ -1,726 +1,833 @@ +using Phantasma.Core.Cryptography; +using Phantasma.Core.Domain; +using Phantasma.Core.Domain.Execution.Enums; +using Phantasma.Core.Domain.Token.Structs; +using Phantasma.Core.Domain.VM; +using Phantasma.Core.Utils; +using Phantasma.Tomb.Compilers; +using System.Diagnostics; +using System.Numerics; + namespace TOMBLib.Tests.Contracts; public class NFTTests { - /* - [Test] - public void NFTs() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - string symbol = "ATEST"; - string name = "Test"; - - var sourceCode = - @"struct someStruct - { - created:timestamp; - creator:address; - royalties:number; - name:string; - description:string; - imageURL:string; - infoURL:string; - } - token " + symbol + @" { - import Runtime; - import Time; - import NFT; - import Map; - global _address:address; - global _owner:address; - global _unlockStorageMap: storage_map; - - property symbol:string = """ + symbol + @"""; - property name:string = """ + name + @"""; - property isBurnable:bool = true; - property isTransferable:bool = true; - - nft myNFT { - - import Call; - import Map; - - property name:string { - return _ROM.name; - } - - property description:string { - return _ROM.description; - } - - property imageURL:string { - return _ROM.imageURL; - } - - property infoURL:string { - return _ROM.infoURL; - } - - property unlockCount:number { - local count:number = Call.interop(""Map.Get"", ""ATEST"", ""_unlockStorageMap"", _tokenID, $TYPE_OF(number)); - return count; - } - } - - import Call; - constructor(owner:address) { - _address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM; - _owner= owner; - NFT.createSeries(owner, $THIS_SYMBOL, 0, 999, TokenSeries.Unique, myNFT); - } - - public mint(dest:address):number { - local rom:someStruct = Struct.someStruct(Time.now(), _address, 1, ""hello"", ""desc"", ""imgURL"", ""info""); - local tokenID:number = NFT.mint(_address, dest, $THIS_SYMBOL, rom, 0, 0); - _unlockStorageMap.set(tokenID, 0); - Call.interop(""Map.Set"", ""_unlockStorageMap"", tokenID, 111); - return tokenID; - } - - public readName(nftID:number): string { - local romInfo:someStruct = NFT.readROM($THIS_SYMBOL, nftID); - return romInfo.name; - } - - public readOwner(nftID:number): address { - local nftInfo:NFT = NFT.read($THIS_SYMBOL, nftID); - return nftInfo.owner; - } - }"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract..asm); - //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract.SubModules.First().asm); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Nexus.CreateToken", keys.Address, contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - var otherKeys = PhantasmaKeys.Generate(); - - simulator.BeginBlock(); - var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "mint", otherKeys.Address). - SpendGas(keys.Address). - EndScript()); - var block = simulator.EndBlock().First(); - - var result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - var obj = VMObject.FromBytes(result); - var nftID = obj.AsNumber(); - Assert.IsTrue(nftID > 0); - - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "readName",nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - obj = VMObject.FromBytes(result); - var nftName = obj.AsString(); - Assert.IsTrue(nftName == "hello"); - - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "readOwner", nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - obj = VMObject.FromBytes(result); - var nftOwner = obj.AsAddress(); - Assert.IsTrue(nftOwner == otherKeys.Address); - - var mempool = new Mempool(simulator.Nexus, 2, 1, System.Text.Encoding.UTF8.GetBytes(symbol), 0, new DummyLogger()); - mempool?.SetKeys(keys); - - var api = new NexusAPI(simulator.Nexus); - - var nft = (TokenDataResult)api.GetNFT(symbol, nftID.ToString(), true); - foreach (var a in nft.properties) - { - switch (a.Key) - { - case "Name": - Assert.IsTrue(a.Value == "hello"); - break; - case "Description": - Assert.IsTrue(a.Value == "desc"); - break; - case "ImageURL": - Assert.IsTrue(a.Value == "imgURL"); - break; - case "InfoURL": - Assert.IsTrue(a.Value == "info"); - break; - case "UnlockCount": - Assert.IsTrue(a.Value == "111"); - break; - - } - } - } - - [Test] - public void NFTWrite() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - string symbol = "ATEST"; - string name = "Test"; - - var sourceCode = - @"struct someStruct - { - created:timestamp; - creator:address; - royalties:number; - name:string; - description:string; - imageURL:string; - infoURL:string; - } - token " + symbol + @" { - import Runtime; - import Time; - import NFT; - import Map; - global _address:address; - global _owner:address; - global _unlockStorageMap: storage_map; - - property symbol:string = """ + symbol+ @"""; - property name:string = """ + name + @"""; - property isBurnable:bool = true; - property isTransferable:bool = true; - - nft myNFT { - - import Call; - import Map; - - property name:string { - return _ROM.name; - } - - property description:string { - return _ROM.description; - } - - property imageURL:string { - return _ROM.imageURL; - } - - property infoURL:string { - return _ROM.infoURL; - } - - property unlockCount:number { - local count:number = Call.interop(""Map.Get"", ""ATEST"", ""_unlockStorageMap"", _tokenID, $TYPE_OF(number)); - return count; - } - } - - import Call; - constructor(owner:address) { - _address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM; - _owner= owner; - NFT.createSeries(owner, $THIS_SYMBOL, 0, 999, TokenSeries.Unique, myNFT); - } - - public mint(dest:address):number { - local rom:someStruct = Struct.someStruct(Time.now(), _address, 1, ""hello"", ""desc"", ""imgURL"", ""info""); - local tokenID:number = NFT.mint(_address, dest, $THIS_SYMBOL, rom, 0, 0); - _unlockStorageMap.set(tokenID, 0); - Call.interop(""Map.Set"", ""_unlockStorageMap"", tokenID, 111); - return tokenID; - } - - public updateNFT(from:address, nftID:number) { - local symbol : string = $THIS_SYMBOL; - NFT.write(from, $THIS_SYMBOL, nftID, 1); - } - - public readNFTRAM(nftID:number): number{ - local ramInfo : number = NFT.readRAM($THIS_SYMBOL, nftID); - return ramInfo; - } - - public readName(nftID:number): string { - local romInfo:someStruct = NFT.readROM($THIS_SYMBOL, nftID); - return romInfo.name; - } - - public readOwner(nftID:number): address { - local nftInfo:NFT = NFT.read($THIS_SYMBOL, nftID); - return nftInfo.owner; - } - }"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract..asm); - //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract.SubModules.First().asm); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Nexus.CreateToken", keys.Address, contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - var otherKeys = PhantasmaKeys.Generate(); - - simulator.BeginBlock(); - var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "mint", otherKeys.Address). - SpendGas(keys.Address). - EndScript()); - var block = simulator.EndBlock().First(); - - var result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - var obj = VMObject.FromBytes(result); - var nftID = obj.AsNumber(); - Assert.IsTrue(nftID > 0); - - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "readName", nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - obj = VMObject.FromBytes(result); - var nftName = obj.AsString(); - Assert.IsTrue(nftName == "hello"); - - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "readOwner", nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - obj = VMObject.FromBytes(result); - var nftOwner = obj.AsAddress(); - Assert.IsTrue(nftOwner == otherKeys.Address); - - // update ram - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "updateNFT", otherKeys.Address.Text, nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - // Read RAM - simulator.BeginBlock(); - tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract(symbol, "readNFTRAM", nftID). - SpendGas(keys.Address). - EndScript()); - block = simulator.EndBlock().First(); - - result = block.GetResultForTransaction(tx.Hash); - Assert.NotNull(result); - obj = VMObject.FromBytes(result); - var ram = obj.AsNumber(); - Assert.IsTrue(ram == 1); - - var mempool = new Mempool(simulator.Nexus, 2, 1, System.Text.Encoding.UTF8.GetBytes(symbol), 0, new DummyLogger()); - mempool?.SetKeys(keys); - - var api = new NexusAPI(simulator.Nexus); - - var nft = (TokenDataResult)api.GetNFT(symbol, nftID.ToString(), true); - foreach (var a in nft.properties) - { - switch (a.Key) - { - case "Name": - Assert.IsTrue(a.Value == "hello"); - break; - case "Description": - Assert.IsTrue(a.Value == "desc"); - break; - case "ImageURL": - Assert.IsTrue(a.Value == "imgURL"); - break; - case "InfoURL": - Assert.IsTrue(a.Value == "info"); - break; - case "UnlockCount": - Assert.IsTrue(a.Value == "111"); - break; - - } - } - } - - [Test] - public void Triggers() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - var sourceCode = - "contract test {\n" + - "import Runtime;\n" + - "import Time;\n" + - "global _address:address;" + - "global _owner:address;" + - "constructor(owner:address) {\n" + - "_address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM;\n" + - "_owner= owner;\n" + - "}\n" + - "public doStuff(from:address)\n" + - "{\n" + - "}\n"+ - "trigger onUpgrade(from:address)\n" + - "{\n" + - " Runtime.expect(from == _address, \"invalid owner address\"\n);" + - " Runtime.expect(Runtime.isWitness(from), \"invalid witness\"\n);" + - "}\n" + - "}\n"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallInterop("Runtime.UpgradeContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()). - SpendGas(keys.Address). - EndScript()); - var ex = Assert.Throws(() => simulator.EndBlock()); - Assert.That(ex.Message, Is.EqualTo("add block @ main failed, reason: OnUpgrade trigger failed @ Runtime_UpgradeContract")); - - } - - [Test] - public void StorageList() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - var sourceCode = - "contract test {\n" + - "import Runtime;\n" + - "import Time;\n" + - "import List;\n" + - "global myList: storage_list;\n" + - "public getCount():number\n" + - "{\n" + - " return myList.count();\n" + - "}\n" + - "public getStuff(index:number):string \n" + - "{\n" + - " return myList.get(index);\n" + - "}\n"+ - "public removeStuff(index:number) \n" + - "{\n" + - " myList.removeAt(index);\n" + - "}\n" + - "public clearStuff() \n" + - "{\n" + - " myList.clear();\n" + - "}\n" + - "public addStuff(stuff:string) \n" + - "{\n" + - " myList.add(stuff);\n" + - "}\n" + - "public replaceStuff(index:number, stuff:string) \n" + - "{\n" + - " myList.replace(index, stuff);\n" + - "}\n" + - "constructor(owner:address) {\n" + - " this.addStuff(\"hello\");\n" + - " this.addStuff(\"world\");\n" + - "}\n" + - "}\n"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - Func fetchListItem = (index) => - { - simulator.BeginBlock(); - var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "getStuff", index). - SpendGas(keys.Address). - EndScript()); - var block = simulator.EndBlock().FirstOrDefault(); - - var bytes = block.GetResultForTransaction(tx.Hash); - Assert.IsTrue(bytes != null); - - var vmObj = Serialization.Unserialize(bytes); - - return vmObj.AsString(); - }; - - Func fetchListCount = () => - { - simulator.BeginBlock(); - var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "getCount"). - SpendGas(keys.Address). - EndScript()); - var block = simulator.EndBlock().FirstOrDefault(); - - var bytes = block.GetResultForTransaction(tx.Hash); - Assert.IsTrue(bytes != null); - - var vmObj = Serialization.Unserialize(bytes); - - return (int)vmObj.AsNumber(); - }; - - string str; - int count; - - str = fetchListItem(0); - Assert.IsTrue(str == "hello"); - - str = fetchListItem(1); - Assert.IsTrue(str == "world"); - - count = fetchListCount(); - Assert.IsTrue(count == 2); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "removeStuff", 0). - SpendGas(keys.Address). - EndScript()); - simulator.EndBlock(); - - count = fetchListCount(); - Assert.IsTrue(count == 1); - - str = fetchListItem(0); - Assert.IsTrue(str == "world"); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "replaceStuff", 0, "A"). - CallContract("test", "addStuff", "B"). - CallContract("test", "addStuff", "C"). - SpendGas(keys.Address). - EndScript()); - simulator.EndBlock(); - - count = fetchListCount(); - Assert.IsTrue(count == 3); - - str = fetchListItem(0); - Assert.IsTrue(str == "A"); - - str = fetchListItem(1); - Assert.IsTrue(str == "B"); - - str = fetchListItem(2); - Assert.IsTrue(str == "C"); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "clearStuff"). - SpendGas(keys.Address). - EndScript()); - simulator.EndBlock(); - - count = fetchListCount(); - Assert.IsTrue(count == 0); - } - - [Test] - public void StorageMap() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - var sourceCode = - "contract test {\n" + - "import Runtime;\n" + - "import Time;\n" + - "import Map;\n" + - "global _storageMap: storage_map;\n" + - "constructor(owner:address) {\n" + - "_storageMap.set(5, \"test1\");\n" + - "}\n" + - "public doStuff(from:address)\n" + - "{\n" + - " local test:string = _storageMap.get(5);\n" + - " Runtime.log(\"this log: \");\n" + - " Runtime.log(test);\n" + - "}\n" + - "}\n"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "doStuff", keys.Address). - SpendGas(keys.Address). - EndScript()); - simulator.EndBlock(); - } - - public struct My_Struct - { - public string name; - public BigInteger value; - } - - - [Test] - public void StorageMapAndStruct() - { - var keys = PhantasmaKeys.Generate(); - var keys2 = PhantasmaKeys.Generate(); - - var nexus = new Nexus("simnet", null, null); - //nexus.SetOracleReader(new OracleSimulator(nexus)); - var simulator = new NexusSimulator(nexus, keys, 1234); - - var sourceCode = - "struct my_struct\n{" + - "name:string;\n" + - "value:number;\n" + - "}\n" + - "contract test {\n" + - "import Runtime;\n" + - "import Time;\n" + - "import Map;\n" + - "global _storageMap: storage_map;\n" + - "public createStruct(key:number, s:string, val:number)\n" + - "{\n" + - "local temp: my_struct = Struct.my_struct(s, val);\n" + - "_storageMap.set(key, temp);\n" + - "}\n" + - "public getStruct(key:number):my_struct\n" + - "{\n" + - "return _storageMap.get(key);\n" + - "}\n" + - "}\n"; - - var parser = new TombLangCompiler(); - var contract = parser.Process(sourceCode).First(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, - () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) - .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) - .SpendGas(keys.Address) - .EndScript()); - simulator.EndBlock(); - - simulator.BeginBlock(); - simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => - ScriptUtils.BeginScript(). - AllowGas(keys.Address, Address.Null, 1, 9999). - CallContract("test", "createStruct", 5, "hello", 123). - SpendGas(keys.Address). - EndScript()); - simulator.EndBlock(); - - var vmObj = simulator.Nexus.RootChain.InvokeContract(simulator.Nexus.RootStorage, "test", "getStruct", 5); - var temp = vmObj.AsStruct(); - Assert.IsTrue(temp.name == "hello"); - Assert.IsTrue(temp.value == 123); - }*/ + + [Test] + public void GetInfusions() + { + var sourceCode = @" +contract test{ + +import NFT; +import Array; + +public testMethod() : Infusion { + local nfts: array = NFT.getInfusions(""SOUL"", 123); + + local first: Infusion = nfts[0]; + + return first; + } +}"; + + /* +public testMethod2():number { + local nfts: array = NFT.getInfusions(""SOUL"", 123); + return Array.length(nfts); +} + */ + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + var asm = contract.asm; + Debug.WriteLine(asm); + + var storage = new Dictionary(new ByteArrayComparer()); + + TestVM vm; + + // call testMethod + var method = contract.abi.FindMethod("testMethod"); + Assert.IsNotNull(method); + + vm = new TestVM(contract, storage, method); + var result = vm.Execute(); + Assert.IsTrue(result == ExecutionState.Halt); + + Assert.IsTrue(vm.Stack.Count == 1); + + var obj = vm.Stack.Pop(); + var returnedValue = obj.AsStruct(); + + Assert.IsTrue(returnedValue.Symbol == "SOUL"); + Assert.IsTrue(returnedValue.Value == 1234); + } + + [Test] + public void GetOwnerships() + { + var sourceCode = @" +contract test{ + +import NFT; +import Array; + +public testMethod(from:address) : array { + local result: array = NFT.getOwnerships(from, ""SOUL""); + return result; + } +}"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + var asm = contract.asm; + Debug.WriteLine(asm); + + var storage = new Dictionary(new ByteArrayComparer()); + + TestVM vm; + + var keys = PhantasmaKeys.Generate(); + + // call testMethod + var method = contract.abi.FindMethod("testMethod"); + Assert.IsNotNull(method); + + vm = new TestVM(contract, storage, method); + vm.Stack.Push(VMObject.FromObject(keys.Address)); + var result = vm.Execute(); + Assert.IsTrue(result == ExecutionState.Halt); + + Assert.IsTrue(vm.Stack.Count == 1); + + var obj = vm.Stack.Pop(); + var array = obj.ToArray(); + + Assert.IsTrue(array.Length == 3); + } + + /* + [Test] + public void NFTs() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + string symbol = "ATEST"; + string name = "Test"; + + var sourceCode = + @"struct someStruct + { + created:timestamp; + creator:address; + royalties:number; + name:string; + description:string; + imageURL:string; + infoURL:string; + } + token " + symbol + @" { + import Runtime; + import Time; + import NFT; + import Map; + global _address:address; + global _owner:address; + global _unlockStorageMap: storage_map; + + property symbol:string = """ + symbol + @"""; + property name:string = """ + name + @"""; + property isBurnable:bool = true; + property isTransferable:bool = true; + + nft myNFT { + + import Call; + import Map; + + property name:string { + return _ROM.name; + } + + property description:string { + return _ROM.description; + } + + property imageURL:string { + return _ROM.imageURL; + } + + property infoURL:string { + return _ROM.infoURL; + } + + property unlockCount:number { + local count:number = Call.interop(""Map.Get"", ""ATEST"", ""_unlockStorageMap"", _tokenID, $TYPE_OF(number)); + return count; + } + } + + import Call; + constructor(owner:address) { + _address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM; + _owner= owner; + NFT.createSeries(owner, $THIS_SYMBOL, 0, 999, TokenSeries.Unique, myNFT); + } + + public mint(dest:address):number { + local rom:someStruct = Struct.someStruct(Time.now(), _address, 1, ""hello"", ""desc"", ""imgURL"", ""info""); + local tokenID:number = NFT.mint(_address, dest, $THIS_SYMBOL, rom, 0, 0); + _unlockStorageMap.set(tokenID, 0); + Call.interop(""Map.Set"", ""_unlockStorageMap"", tokenID, 111); + return tokenID; + } + + public readName(nftID:number): string { + local romInfo:someStruct = NFT.readROM($THIS_SYMBOL, nftID); + return romInfo.name; + } + + public readOwner(nftID:number): address { + local nftInfo:NFT = NFT.read($THIS_SYMBOL, nftID); + return nftInfo.owner; + } + }"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract..asm); + //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract.SubModules.First().asm); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Nexus.CreateToken", keys.Address, contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + var otherKeys = PhantasmaKeys.Generate(); + + simulator.BeginBlock(); + var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "mint", otherKeys.Address). + SpendGas(keys.Address). + EndScript()); + var block = simulator.EndBlock().First(); + + var result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + var obj = VMObject.FromBytes(result); + var nftID = obj.AsNumber(); + Assert.IsTrue(nftID > 0); + + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "readName",nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + obj = VMObject.FromBytes(result); + var nftName = obj.AsString(); + Assert.IsTrue(nftName == "hello"); + + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "readOwner", nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + obj = VMObject.FromBytes(result); + var nftOwner = obj.AsAddress(); + Assert.IsTrue(nftOwner == otherKeys.Address); + + var mempool = new Mempool(simulator.Nexus, 2, 1, System.Text.Encoding.UTF8.GetBytes(symbol), 0, new DummyLogger()); + mempool?.SetKeys(keys); + + var api = new NexusAPI(simulator.Nexus); + + var nft = (TokenDataResult)api.GetNFT(symbol, nftID.ToString(), true); + foreach (var a in nft.properties) + { + switch (a.Key) + { + case "Name": + Assert.IsTrue(a.Value == "hello"); + break; + case "Description": + Assert.IsTrue(a.Value == "desc"); + break; + case "ImageURL": + Assert.IsTrue(a.Value == "imgURL"); + break; + case "InfoURL": + Assert.IsTrue(a.Value == "info"); + break; + case "UnlockCount": + Assert.IsTrue(a.Value == "111"); + break; + + } + } + } + + [Test] + public void NFTWrite() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + string symbol = "ATEST"; + string name = "Test"; + + var sourceCode = + @"struct someStruct + { + created:timestamp; + creator:address; + royalties:number; + name:string; + description:string; + imageURL:string; + infoURL:string; + } + token " + symbol + @" { + import Runtime; + import Time; + import NFT; + import Map; + global _address:address; + global _owner:address; + global _unlockStorageMap: storage_map; + + property symbol:string = """ + symbol+ @"""; + property name:string = """ + name + @"""; + property isBurnable:bool = true; + property isTransferable:bool = true; + + nft myNFT { + + import Call; + import Map; + + property name:string { + return _ROM.name; + } + + property description:string { + return _ROM.description; + } + + property imageURL:string { + return _ROM.imageURL; + } + + property infoURL:string { + return _ROM.infoURL; + } + + property unlockCount:number { + local count:number = Call.interop(""Map.Get"", ""ATEST"", ""_unlockStorageMap"", _tokenID, $TYPE_OF(number)); + return count; + } + } + + import Call; + constructor(owner:address) { + _address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM; + _owner= owner; + NFT.createSeries(owner, $THIS_SYMBOL, 0, 999, TokenSeries.Unique, myNFT); + } + + public mint(dest:address):number { + local rom:someStruct = Struct.someStruct(Time.now(), _address, 1, ""hello"", ""desc"", ""imgURL"", ""info""); + local tokenID:number = NFT.mint(_address, dest, $THIS_SYMBOL, rom, 0, 0); + _unlockStorageMap.set(tokenID, 0); + Call.interop(""Map.Set"", ""_unlockStorageMap"", tokenID, 111); + return tokenID; + } + + public updateNFT(from:address, nftID:number) { + local symbol : string = $THIS_SYMBOL; + NFT.write(from, $THIS_SYMBOL, nftID, 1); + } + + public readNFTRAM(nftID:number): number{ + local ramInfo : number = NFT.readRAM($THIS_SYMBOL, nftID); + return ramInfo; + } + + public readName(nftID:number): string { + local romInfo:someStruct = NFT.readROM($THIS_SYMBOL, nftID); + return romInfo.name; + } + + public readOwner(nftID:number): address { + local nftInfo:NFT = NFT.read($THIS_SYMBOL, nftID); + return nftInfo.owner; + } + }"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract..asm); + //System.IO.File.WriteAllText(@"/tmp/asm.asm", contract.SubModules.First().asm); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Nexus.CreateToken", keys.Address, contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + var otherKeys = PhantasmaKeys.Generate(); + + simulator.BeginBlock(); + var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "mint", otherKeys.Address). + SpendGas(keys.Address). + EndScript()); + var block = simulator.EndBlock().First(); + + var result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + var obj = VMObject.FromBytes(result); + var nftID = obj.AsNumber(); + Assert.IsTrue(nftID > 0); + + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "readName", nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + obj = VMObject.FromBytes(result); + var nftName = obj.AsString(); + Assert.IsTrue(nftName == "hello"); + + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "readOwner", nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + obj = VMObject.FromBytes(result); + var nftOwner = obj.AsAddress(); + Assert.IsTrue(nftOwner == otherKeys.Address); + + // update ram + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "updateNFT", otherKeys.Address.Text, nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + // Read RAM + simulator.BeginBlock(); + tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.None, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract(symbol, "readNFTRAM", nftID). + SpendGas(keys.Address). + EndScript()); + block = simulator.EndBlock().First(); + + result = block.GetResultForTransaction(tx.Hash); + Assert.NotNull(result); + obj = VMObject.FromBytes(result); + var ram = obj.AsNumber(); + Assert.IsTrue(ram == 1); + + var mempool = new Mempool(simulator.Nexus, 2, 1, System.Text.Encoding.UTF8.GetBytes(symbol), 0, new DummyLogger()); + mempool?.SetKeys(keys); + + var api = new NexusAPI(simulator.Nexus); + + var nft = (TokenDataResult)api.GetNFT(symbol, nftID.ToString(), true); + foreach (var a in nft.properties) + { + switch (a.Key) + { + case "Name": + Assert.IsTrue(a.Value == "hello"); + break; + case "Description": + Assert.IsTrue(a.Value == "desc"); + break; + case "ImageURL": + Assert.IsTrue(a.Value == "imgURL"); + break; + case "InfoURL": + Assert.IsTrue(a.Value == "info"); + break; + case "UnlockCount": + Assert.IsTrue(a.Value == "111"); + break; + + } + } + } + + [Test] + public void Triggers() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + var sourceCode = + "contract test {\n" + + "import Runtime;\n" + + "import Time;\n" + + "global _address:address;" + + "global _owner:address;" + + "constructor(owner:address) {\n" + + "_address = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM;\n" + + "_owner= owner;\n" + + "}\n" + + "public doStuff(from:address)\n" + + "{\n" + + "}\n"+ + "trigger onUpgrade(from:address)\n" + + "{\n" + + " Runtime.expect(from == _address, \"invalid owner address\"\n);" + + " Runtime.expect(Runtime.isWitness(from), \"invalid witness\"\n);" + + "}\n" + + "}\n"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallInterop("Runtime.UpgradeContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()). + SpendGas(keys.Address). + EndScript()); + var ex = Assert.Throws(() => simulator.EndBlock()); + Assert.That(ex.Message, Is.EqualTo("add block @ main failed, reason: OnUpgrade trigger failed @ Runtime_UpgradeContract")); + + } + + [Test] + public void StorageList() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + var sourceCode = + "contract test {\n" + + "import Runtime;\n" + + "import Time;\n" + + "import List;\n" + + "global myList: storage_list;\n" + + "public getCount():number\n" + + "{\n" + + " return myList.count();\n" + + "}\n" + + "public getStuff(index:number):string \n" + + "{\n" + + " return myList.get(index);\n" + + "}\n"+ + "public removeStuff(index:number) \n" + + "{\n" + + " myList.removeAt(index);\n" + + "}\n" + + "public clearStuff() \n" + + "{\n" + + " myList.clear();\n" + + "}\n" + + "public addStuff(stuff:string) \n" + + "{\n" + + " myList.add(stuff);\n" + + "}\n" + + "public replaceStuff(index:number, stuff:string) \n" + + "{\n" + + " myList.replace(index, stuff);\n" + + "}\n" + + "constructor(owner:address) {\n" + + " this.addStuff(\"hello\");\n" + + " this.addStuff(\"world\");\n" + + "}\n" + + "}\n"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + Func fetchListItem = (index) => + { + simulator.BeginBlock(); + var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "getStuff", index). + SpendGas(keys.Address). + EndScript()); + var block = simulator.EndBlock().FirstOrDefault(); + + var bytes = block.GetResultForTransaction(tx.Hash); + Assert.IsTrue(bytes != null); + + var vmObj = Serialization.Unserialize(bytes); + + return vmObj.AsString(); + }; + + Func fetchListCount = () => + { + simulator.BeginBlock(); + var tx = simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "getCount"). + SpendGas(keys.Address). + EndScript()); + var block = simulator.EndBlock().FirstOrDefault(); + + var bytes = block.GetResultForTransaction(tx.Hash); + Assert.IsTrue(bytes != null); + + var vmObj = Serialization.Unserialize(bytes); + + return (int)vmObj.AsNumber(); + }; + + string str; + int count; + + str = fetchListItem(0); + Assert.IsTrue(str == "hello"); + + str = fetchListItem(1); + Assert.IsTrue(str == "world"); + + count = fetchListCount(); + Assert.IsTrue(count == 2); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "removeStuff", 0). + SpendGas(keys.Address). + EndScript()); + simulator.EndBlock(); + + count = fetchListCount(); + Assert.IsTrue(count == 1); + + str = fetchListItem(0); + Assert.IsTrue(str == "world"); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "replaceStuff", 0, "A"). + CallContract("test", "addStuff", "B"). + CallContract("test", "addStuff", "C"). + SpendGas(keys.Address). + EndScript()); + simulator.EndBlock(); + + count = fetchListCount(); + Assert.IsTrue(count == 3); + + str = fetchListItem(0); + Assert.IsTrue(str == "A"); + + str = fetchListItem(1); + Assert.IsTrue(str == "B"); + + str = fetchListItem(2); + Assert.IsTrue(str == "C"); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "clearStuff"). + SpendGas(keys.Address). + EndScript()); + simulator.EndBlock(); + + count = fetchListCount(); + Assert.IsTrue(count == 0); + } + + [Test] + public void StorageMap() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + var sourceCode = + "contract test {\n" + + "import Runtime;\n" + + "import Time;\n" + + "import Map;\n" + + "global _storageMap: storage_map;\n" + + "constructor(owner:address) {\n" + + "_storageMap.set(5, \"test1\");\n" + + "}\n" + + "public doStuff(from:address)\n" + + "{\n" + + " local test:string = _storageMap.get(5);\n" + + " Runtime.log(\"this log: \");\n" + + " Runtime.log(test);\n" + + "}\n" + + "}\n"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "doStuff", keys.Address). + SpendGas(keys.Address). + EndScript()); + simulator.EndBlock(); + } + + public struct My_Struct + { + public string name; + public BigInteger value; + } + + + [Test] + public void StorageMapAndStruct() + { + var keys = PhantasmaKeys.Generate(); + var keys2 = PhantasmaKeys.Generate(); + + var nexus = new Nexus("simnet", null, null); + //nexus.SetOracleReader(new OracleSimulator(nexus)); + var simulator = new NexusSimulator(nexus, keys, 1234); + + var sourceCode = + "struct my_struct\n{" + + "name:string;\n" + + "value:number;\n" + + "}\n" + + "contract test {\n" + + "import Runtime;\n" + + "import Time;\n" + + "import Map;\n" + + "global _storageMap: storage_map;\n" + + "public createStruct(key:number, s:string, val:number)\n" + + "{\n" + + "local temp: my_struct = Struct.my_struct(s, val);\n" + + "_storageMap.set(key, temp);\n" + + "}\n" + + "public getStruct(key:number):my_struct\n" + + "{\n" + + "return _storageMap.get(key);\n" + + "}\n" + + "}\n"; + + var parser = new TombLangCompiler(); + var contract = parser.Process(sourceCode).First(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, + () => ScriptUtils.BeginScript().AllowGas(keys.Address, Address.Null, 1, 9999) + .CallInterop("Runtime.DeployContract", keys.Address, "test", contract.script, contract.abi.ToByteArray()) + .SpendGas(keys.Address) + .EndScript()); + simulator.EndBlock(); + + simulator.BeginBlock(); + simulator.GenerateCustomTransaction(keys, ProofOfWork.Minimal, () => + ScriptUtils.BeginScript(). + AllowGas(keys.Address, Address.Null, 1, 9999). + CallContract("test", "createStruct", 5, "hello", 123). + SpendGas(keys.Address). + EndScript()); + simulator.EndBlock(); + + var vmObj = simulator.Nexus.RootChain.InvokeContract(simulator.Nexus.RootStorage, "test", "getStruct", 5); + var temp = vmObj.AsStruct(); + Assert.IsTrue(temp.name == "hello"); + Assert.IsTrue(temp.value == 123); + }*/ } \ No newline at end of file diff --git a/Library/tests/TestVM.cs b/Library/tests/TestVM.cs index 86cd6bd..0fb043a 100644 --- a/Library/tests/TestVM.cs +++ b/Library/tests/TestVM.cs @@ -7,11 +7,12 @@ using Phantasma.Core.Domain.Contract; using Phantasma.Core.Domain.Execution.Enums; using Phantasma.Core.Domain.Serializer; +using Phantasma.Core.Domain.Token.Structs; using Phantasma.Core.Domain.VM; using Phantasma.Core.Domain.VM.Enums; using Phantasma.Core.Numerics; using Phantasma.Tomb.CodeGen; - +using System.Numerics; using ExecutionContext = Phantasma.Core.Domain.Execution.ExecutionContext; namespace TOMBLib.Tests; @@ -46,6 +47,7 @@ public TestVM(Module module, Dictionary storage, ContractMethod RegisterMethod("Runtime.TransactionHash", Runtime_TransactionHash); RegisterMethod("Runtime.Context", Runtime_Context); RegisterMethod("Runtime.ReadInfusions", Runtime_ReadInfusions); + RegisterMethod("Runtime.GetOwnerships", Runtime_GetOwnerships); RegisterMethod("Runtime.GetAvailableTokenSymbols", Runtime_GetAvailableTokenSymbols); @@ -192,12 +194,31 @@ private ExecutionState Runtime_TransactionHash(VirtualMachine vm) return ExecutionState.Running; } + + private ExecutionState Runtime_GetOwnerships(VirtualMachine vm) + { + var from = vm.Stack.Pop(); + var symbol = vm.PopString("symbol"); + + var array = new BigInteger[] { 123, 456, 789 }; + + var val = VMObject.FromArray(array); + this.Stack.Push(val); + + return ExecutionState.Running; + } + private ExecutionState Runtime_ReadInfusions(VirtualMachine vm) { var symbol = vm.PopString("symbol"); var id = vm.PopNumber("token_id"); - var val = Serialization.Unserialize(Base16.Decode("0102030100081E0102040653796D626F6C0404534F554C040556616C7565030500CA9A3B0003020100083A0102040653796D626F6C04044E434F4C040556616C756503219905474F01A1DC34E8C3DB6657A297B6A3F69EE81E7BEC97DF171F79231AAD1C00")); + var infusion = new TokenInfusion("SOUL", 1234); + + var infusionArray = new TokenInfusion[] { infusion }; + + var val = VMObject.FromArray(infusionArray); + this.Stack.Push(val); return ExecutionState.Running; diff --git a/README.md b/README.md index a18e347..f8d2c49 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,9 @@ The following libraries can be imported into a contract. | NFT.createSeries(from:Address, symbol:String, seriesID:Number, maxSupply:Number, mode:Enum, nft:Module) | None | Creates a series of NFTs. | | NFT.readROM(symbol:String, id:Number) | T | Returns the ROM by the NFTID. | | NFT.readRAM(symbol:String, id:Number) | T | Returns the RAM by the NFTID. | -| NFT.availableSymbols() | Array | Returns list with symbols of all deployed non-fungible tokens. | +| NFT.getInfusions(symbol:String, id:Number) | Array | Returns list with all tokens infused into a specific token. | +| NFT.getOwnerships(from:Address, symbol:String) | Array | Returns list with token ids of NFTs owned by the specified address and symbol. | +| NFT.availableSymbols() | Array | Returns list with symbols of all deployed non-fungible tokens. | ### Account @@ -1478,6 +1480,48 @@ token NACHO { ``` +## Listing ownerships of NFTs +Many times it's necessary to obtain a list of NFTs owned by a specific address. +For that you can use the NFT.getOwnerships() method. +Note that this method requires a symbol. If you need to know all the owned NFTs of a specific address, call NFT.availableSymbols and iterate over it. + +```c# +contract test { + +import NFT; +import Array; + +public getOwnedList(from:address) : array { + local symbol: string = "MYTOK"; + local result: array = NFT.getOwnerships(from, symbol); + return result; + } +} +``` + +## Listing NFTs infused inside other NFTs +Many times it's necessary to obtain a list of NFTs infused into a specific NFT. +For that you can use the NFT.getInfusions() method. +It will return an array of Infusion structs, that have a Symbol: string and Value: Number as fields. +Note that the Value field will be an amount for fungible-tokens and a tokenID for NFTs. + +```c# +contract test { + +import NFT; +import Array; + +public getFirstInfusedToken(infusedTokenID: number) : Infusion { + local nfts: array = NFT.getInfusions("MYTOK", infusedTokenID); + + local first: Infusion = nfts[0]; + + return first; + } +} +``` + + ## Contract Macros Besides the macros listed in the Available macros section, each of your contracts will also come with its own macros.
From 5e325d48c022fbe4b0c07ad8fb2a8538cbdc54db Mon Sep 17 00:00:00 2001 From: Sergio Flores Date: Sat, 5 Aug 2023 16:12:42 +0100 Subject: [PATCH 4/4] Updated Nugets --- Compiler/TombCompiler.csproj | 6 ------ Library/src/TOMBLib.csproj | 5 ++--- Library/tests/TOMBLib.Tests.csproj | 2 -- TombCompiler.sln | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Compiler/TombCompiler.csproj b/Compiler/TombCompiler.csproj index 5f35738..ca6bb32 100644 --- a/Compiler/TombCompiler.csproj +++ b/Compiler/TombCompiler.csproj @@ -8,12 +8,6 @@ - - - - - - diff --git a/Library/src/TOMBLib.csproj b/Library/src/TOMBLib.csproj index f23f5e7..c60ff8b 100644 --- a/Library/src/TOMBLib.csproj +++ b/Library/src/TOMBLib.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -21,8 +21,7 @@ - - + diff --git a/Library/tests/TOMBLib.Tests.csproj b/Library/tests/TOMBLib.Tests.csproj index 4d8052c..c5fccb1 100644 --- a/Library/tests/TOMBLib.Tests.csproj +++ b/Library/tests/TOMBLib.Tests.csproj @@ -19,8 +19,6 @@ - - diff --git a/TombCompiler.sln b/TombCompiler.sln index d08c574..b8e8f38 100644 --- a/TombCompiler.sln +++ b/TombCompiler.sln @@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TombCompiler", "Compiler\To EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TOMBLib", "Library\src\TOMBLib.csproj", "{86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TOMBLib.Tests", "Library\tests\TOMBLib.Tests.csproj", "{EA79025B-F50F-4608-B2BC-77D776AE99EB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TOMBLib.Tests", "Library\tests\TOMBLib.Tests.csproj", "{EA79025B-F50F-4608-B2BC-77D776AE99EB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution