public void Compile() { foreach (var subModule in this.SubModules) { subModule.Compile(); } var sb = new CodeGenerator(); abi = this.GenerateCode(sb); Compiler.Instance.VerifyRegisters(); asm = sb.ToString(); var lines = asm.Split('\n'); DebugInfo temp; Dictionary <string, int> labels; script = AssemblerUtils.BuildScript(lines, this.Name, out temp, out labels); this.debugInfo = temp; lines = AssemblerUtils.CommentOffsets(lines, this.debugInfo).ToArray(); ProcessABI(abi, this.debugInfo); asm = string.Join('\n', lines); }
public Transaction GenerateToken(PhantasmaKeys owner, string symbol, string name, BigInteger totalSupply, int decimals, TokenFlags flags, byte[] tokenScript = null) { if (tokenScript == null) { // small script that restricts minting of tokens to transactions where the owner is a witness var addressStr = Base16.Encode(owner.Address.ToByteArray()); var scriptString = new string[] { $"alias r1, $triggerMint", $"alias r2, $currentTrigger", $"alias r3, $result", $"alias r4, $owner", $@"load $triggerMint, ""{AccountTrigger.OnMint}""", $"pop $currentTrigger", $"equal $triggerMint, $currentTrigger, $result", $"jmpif $result, @mintHandler", $"jmp @end", $"@mintHandler: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"throw", $"@end: ret" }; tokenScript = AssemblerUtils.BuildScript(scriptString); } var script = ScriptUtils. BeginScript(). AllowGas(owner.Address, Address.Null, MinimumFee, 9999). CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript). SpendGas(owner.Address). EndScript(); var tx = MakeTransaction(owner, ProofOfWork.Minimal, Nexus.RootChain, script); return tx; }
public Transaction GenerateToken(PhantasmaKeys owner, string symbol, string name, BigInteger totalSupply, int decimals, TokenFlags flags, byte[] tokenScript = null, Dictionary <string, int> labels = null, IEnumerable <ContractMethod> customMethods = null) { var version = Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag); if (labels == null) { labels = new Dictionary <string, int>(); } if (tokenScript == null) { // small script that restricts minting of tokens to transactions where the owner is a witness var addressStr = Base16.Encode(owner.Address.ToByteArray()); string[] scriptString; if (version >= 4) { scriptString = new string[] { $"alias r3, $result", $"alias r4, $owner", $"@{AccountTrigger.OnMint}: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; } else { scriptString = new string[] { $"alias r1, $triggerMint", $"alias r2, $currentTrigger", $"alias r3, $result", $"alias r4, $owner", $@"load $triggerMint, ""{AccountTrigger.OnMint}""", $"pop $currentTrigger", $"equal $triggerMint, $currentTrigger, $result", $"jmpif $result, @mintHandler", $"jmp @end", $"@mintHandler: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; } DebugInfo debugInfo; tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels); } var sb = ScriptUtils. BeginScript(). AllowGas(owner.Address, Address.Null, MinimumFee, 9999); if (version >= 4) { var triggerMap = new Dictionary <AccountTrigger, int>(); var onMintLabel = AccountTrigger.OnMint.ToString(); if (labels.ContainsKey(onMintLabel)) { triggerMap[AccountTrigger.OnMint] = labels[onMintLabel]; } var methods = AccountContract.GetTriggersForABI(triggerMap); if (customMethods != null) { methods = methods.Concat(customMethods); } var abi = new ContractInterface(methods, Enumerable.Empty <ContractEvent>()); var abiBytes = abi.ToByteArray(); sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript, abiBytes); } else { sb.CallInterop("Nexus.CreateToken", owner.Address, symbol, name, totalSupply, decimals, flags, tokenScript); } if (!flags.HasFlag(TokenFlags.Fungible)) { ContractInterface nftABI; byte[] nftScript; NFTUtils.GenerateNFTDummyScript(symbol, name, name, "http://simulator/nft/*", "http://simulator/img/*", out nftScript, out nftABI); sb.CallInterop("Nexus.CreateTokenSeries", owner.Address, symbol, new BigInteger(0), totalSupply, TokenSeriesMode.Unique, nftScript, nftABI.ToByteArray()); } sb.SpendGas(owner.Address); var script = sb.EndScript(); var tx = MakeTransaction(owner, ProofOfWork.Minimal, Nexus.RootChain, script); return(tx); }
public void TestAutoSendAddress() { var test = CreateAPI(); var simulator = test.simulator; var owner = test.owner; var testUser = PhantasmaKeys.Generate(); var autoSender = PhantasmaKeys.Generate(); var receiver = PhantasmaKeys.Generate(); var node = PhantasmaKeys.FromWIF(nodeWIF); var nexus = simulator.Nexus; var api = test.api; var symbol = DomainSettings.StakingTokenSymbol; var senderAddressStr = Base16.Encode(autoSender.Address.ToByteArray()); var receivingAddressStr = Base16.Encode(receiver.Address.ToByteArray()); string[] scriptString = new string[] { $"alias r1, $triggerReceive", $"alias r2, $currentTrigger", $"alias r3, $comparisonResult", $@"load $triggerReceive, ""{AccountTrigger.OnReceive}""", $"pop $currentTrigger", $"equal $triggerReceive, $currentTrigger, $comparisonResult", $"jmpif $comparisonResult, @receiveHandler", $"jmp @end", $"@receiveHandler: nop", $"alias r4, $tokenContract", $"alias r5, $sourceAddress", $"alias r6, $targetAddress", $"alias r7, $receivedAmount", $"alias r8, $symbol", $"alias r9, $methodName", $"pop $symbol", $"pop $sourceAddress", $"pop $receivedAmount", $"load r11 0x{receivingAddressStr}", $"push r11", $@"extcall ""Address()""", $"pop $targetAddress", $@"load $methodName, ""TransferTokens""", $"push $receivedAmount", $"push $symbol", $"push $targetAddress", $"push $sourceAddress", $@"push $methodName", //switch to token contract $@"load r12, ""token""", $"ctx r12, $tokenContract", $"switch $tokenContract", $"@end: ret" }; var script = AssemblerUtils.BuildScript(scriptString); simulator.BeginBlock(); simulator.GenerateTransfer(owner, autoSender.Address, simulator.Nexus.RootChain, DomainSettings.FuelTokenSymbol, 100000); simulator.GenerateCustomTransaction(autoSender, ProofOfWork.None, () => ScriptUtils.BeginScript().AllowGas(autoSender.Address, Address.Null, 1, 9999) .CallContract("account", "RegisterScript", autoSender.Address, script).SpendGas(autoSender.Address) .EndScript()); simulator.EndBlock(); simulator.BeginBlock(); simulator.GenerateTransfer(owner, autoSender.Address, simulator.Nexus.RootChain, symbol, 30000); simulator.EndBlock(); var token = simulator.Nexus.GetTokenInfo(simulator.Nexus.RootStorage, symbol); var balance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, token, receiver.Address); Assert.IsTrue(balance == 30000); }
public static byte[] GenerateMultisigScript(MultisigSettings settings) { var scriptHead = new List <string>(); bool isTrue = true; bool isFalse = false; for (int i = 0; i < settings.addressArray.Length; i++) { scriptHead.Add($"load r1 { i }"); scriptHead.Add($"load r2 0x{ Base16.Encode(settings.addressArray[i].PublicKey) }"); scriptHead.Add($"put r2 r3 r1"); } // needs to check send/receive triggers! NOT YET DONE var scriptTail = new string[] { "alias r4 $minSigned", "alias r5 $addrCount", "alias r6 $i", "alias r7 $loopResult", "alias r8 $interResult", "alias r9 $result", "alias r10 $signed", "alias r11 $temp", "alias r12 $true", // check if we are sending/receiving "alias r13 $triggerSend", "alias r14 $currentTrigger", "alias r15 $false", $"load $false { isFalse }", $@"load $triggerSend, ""{AccountContract.TriggerSend}""", $"pop $currentTrigger", $"equal $triggerSend, $currentTrigger, $result", $"jmpnot $result, @finishNotSend", $"load $minSigned { settings.signeeCount }", $"load $addrCount { settings.addressArray.Length }", "load $signed 0", $"load $true { isTrue }", "load $i 0", "@loop: ", "lt $i $addrCount $loopResult", "jmpnot $loopResult @checkSigned", // get address from array "get r3 $temp $i", // push address to stack "push $temp", // convert to address object "extcall \"Address()\"", "call @checkWitness", "equal $interResult, $true, $result", "jmpif $result @increm", "inc $i", "jmp @loop", "@increm:", "inc $signed", "inc $i", "jmp @loop", "@checkSigned: ", "gte $signed $minSigned $result", "jmpif $result @finish", "jmpnot $result @break", "ret", "@finish:", "push $result", "ret", "@finishNotSend:", "push $true", "ret", "@break:", "throw", "@checkWitness: ", "extcall \"CheckWitness()\"", "pop $interResult", "ret", }; var scriptString = scriptHead.Concat(scriptTail.ToArray()).ToArray(); // temp test log to verify script List <string> tempList = new List <string>(scriptString); tempList.ForEach(Console.WriteLine); // build script var script = AssemblerUtils.BuildScript(scriptString); return(script); }
public Transaction GenerateToken(PhantasmaKeys owner, string symbol, string name, BigInteger totalSupply, int decimals, TokenFlags flags, byte[] tokenScript = null, Dictionary <string, int> labels = null, IEnumerable <ContractMethod> customMethods = null, uint seriesID = 0) { var version = _cli.Nexus.GetGovernanceValue(_cli.Nexus.RootStorage, Nexus.NexusProtocolVersionTag); labels ??= new Dictionary <string, int>(); if (tokenScript == null) { // small script that restricts minting of tokens to transactions where the owner is a witness var addressStr = Base16.Encode(owner.Address.ToByteArray()); string[] scriptString; if (version >= 4) { scriptString = new[] { $"alias r3, $result", $"alias r4, $owner", $"@{AccountTrigger.OnMint}: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@getOwner: nop", $"load $owner 0x{addressStr}", "push $owner", $"jmp @end", $"@getSymbol: nop", $"load r0 \"" + symbol + "\"", "push r0", $"jmp @end", $"@getName: nop", $"load r0 \"" + name + "\"", "push r0", $"jmp @end", $"@getMaxSupply: nop", $"load r0 " + totalSupply + "", "push r0", $"jmp @end", $"@getDecimals: nop", $"load r0 " + decimals + "", "push r0", $"jmp @end", $"@getTokenFlags: nop", $"load r0 " + (int)flags + "", "push r0", $"jmp @end", $"@end: ret" }; } else { scriptString = new string[] { $"alias r1, $triggerMint", $"alias r2, $currentTrigger", $"alias r3, $result", $"alias r4, $owner", $@"load $triggerMint, ""{AccountTrigger.OnMint}""", $"pop $currentTrigger", $"equal $triggerMint, $currentTrigger, $result", $"jmpif $result, @mintHandler", $"jmp @end", $"@mintHandler: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; } DebugInfo debugInfo; tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels); } var sb = ScriptUtils. BeginScript(). AllowGas(owner.Address, Address.Null, 100000, 9999); if (version >= 4) { var triggerMap = new Dictionary <AccountTrigger, int>(); var onMintLabel = AccountTrigger.OnMint.ToString(); if (labels.ContainsKey(onMintLabel)) { triggerMap[AccountTrigger.OnMint] = labels[onMintLabel]; } var methods = AccountContract.GetTriggersForABI(triggerMap); if (version >= 6) { methods = methods.Concat(new ContractMethod[] { new ("getOwner", VMType.Object, labels, new ContractParameter[0]), new ("getSymbol", VMType.String, labels, new ContractParameter[0]), new ("getName", VMType.String, labels, new ContractParameter[0]), new ("getDecimals", VMType.Number, labels, new ContractParameter[0]), new ("getMaxSupply", VMType.Number, labels, new ContractParameter[0]), new ("getTokenFlags", VMType.Enum, labels, new ContractParameter[0]), });
public static byte[] GenerateScriptFromString(VarType type, string src) { src = src.Substring(1, src.Length - 2); // remove "" delimiters var tokens = new List <StringToken>(); var sb = new StringBuilder(); bool insideTags = false; for (int i = 0; i < src.Length; i++) { var ch = src[i]; switch (ch) { case '{': if (insideTags) { throw new CompilerException("Open declaration tag mismatch"); } if (sb.Length > 0) { tokens.Add(new StringToken(false, sb.ToString())); sb.Clear(); } insideTags = true; break; case '}': if (!insideTags) { throw new CompilerException("Close declaration tag mismatch"); } if (sb.Length == 0) { throw new CompilerException("Empty declaration tag"); } insideTags = false; tokens.Add(new StringToken(true, sb.ToString())); sb.Clear(); break; default: sb.Append(ch); break; } } if (sb.Length > 0) { tokens.Add(new StringToken(false, sb.ToString())); } sb.Clear(); sb.AppendLine("POP r2"); // address sb.AppendLine("POP r3"); // data sb.AppendLine("LOAD r0 \"\""); foreach (var token in tokens) { if (token.dynamic) { if (token.value == "address") { sb.AppendLine($"CAST r2 r1 #String"); } else if (token.value == "data") { if (type.Kind == VarKind.Struct) { throw new CompilerException($"struct fields not specified"); } else { sb.AppendLine($"CAST r3 r1 #String"); } } else if (token.value.StartsWith("data.")) { throw new CompilerException($"Struct tags not implemented"); } else { throw new CompilerException($"Invalid declaration tag: {token.value}"); } } else { sb.AppendLine($"LOAD r1 \"{token.value}\""); } sb.AppendLine("ADD r0 r1 r0"); } sb.AppendLine("PUSH r0"); // return result sb.AppendLine("RET"); var asm = sb.ToString(); var script = AssemblerUtils.BuildScript(asm); return(script); }
public static byte[] GenerateMultisigScript(MultisigSettings settings) { throw new Exception("NOT SUPPORTED YET"); var scriptHead = new List <string>(); bool isTrue = true; for (int i = 0; i < settings.addressArray.Length; i++) { scriptHead.Add($"load r1 { i }"); scriptHead.Add($"load r2 \"{ settings.addressArray[i] }\""); scriptHead.Add($"put r2 r3 r1"); } // needs to check send/receive triggers! NOT YET DONE var scriptTail = new string[] { "alias r4 $minSigned", "alias r5 $addrCount", "alias r6 $i", "alias r7 $loopResult", "alias r8 $interResult", "alias r9 $result", "alias r10 $signed", "alias r11 $temp", "alias r12 $true", $"load $minSigned { settings.signeeCount }", $"load $addrCount { settings.addressArray.Length }", "load $signed 0", $"load $true { isTrue }", "load $i 0", "@loop: ", "lt $i $addrCount $loopResult", "jmpnot $loopResult @checkSigned", // get address from array "get r3 $temp $i", // push address to stack "push $temp", "call @checkWitness", "equal $interResult, $true, $result", "jmpif $result @increm", "inc $i", "jmp @loop", "@increm:", "inc $signed", "inc $i", "jmp @loop", "@checkSigned: ", "gte $signed $minSigned $result", "jmpif $result @finish", "jmpnot $result @break", "ret", "@finish:", "push $result", "ret", "@break:", "throw", "@checkWitness: ", "extcall \"CheckWitness()\"", "pop $interResult", "ret", }; var scriptString = scriptHead.Concat(scriptTail.ToArray()).ToArray(); // temp test log to verify script List <string> tempList = new List <string>(scriptString); tempList.ForEach(Console.WriteLine); // build script var script = AssemblerUtils.BuildScript(scriptString); return(script); }
static byte[] GenCreateToken() { Console.Write("Token symbol? "); string symbol = Console.ReadLine(); if (!ValidationUtils.IsValidTicker(symbol)) { Console.Write("Invalid token symbol"); return(null); } Console.Write("Token name? "); string name = Console.ReadLine(); TokenFlags flags = TokenFlags.Transferable; var possibleValues = new[] { TokenFlags.Burnable, TokenFlags.Divisible, TokenFlags.Finite, TokenFlags.Fungible }; foreach (var val in possibleValues) { if (FetchAnswer($"Is {symbol} {val}?")) { flags |= val; } } int decimals; if (flags.HasFlag(TokenFlags.Divisible)) { Console.Write($"How many decimals {symbol} has?: "); if (!int.TryParse(Console.ReadLine(), out decimals) || decimals < 0 || decimals > 18) { Console.Write("Invalid decimals"); return(null); } } else { decimals = 0; } BigInteger maxSupply; if (flags.HasFlag(TokenFlags.Finite)) { Console.Write($"What is the max supply of {symbol}?: "); decimal val; if (!decimal.TryParse(Console.ReadLine(), out val) || val <= 0) { Console.Write("Invalid decimals"); return(null); } maxSupply = UnitConversion.ToBigInteger(val, decimals); } else { maxSupply = 0; } var labels = new Dictionary <string, int>(); var addressStr = Base16.Encode(signerKeys.Address.ToByteArray()); string[] scriptString; scriptString = new string[] { $"alias r3, $result", $"alias r4, $owner", $"@{AccountTrigger.OnMint}: nop", $"load $owner 0x{addressStr}", "push $owner", "extcall \"Address()\"", "extcall \"Runtime.IsWitness\"", "pop $result", $"jmpif $result, @end", $"load r0 \"invalid witness\"", $"throw r0", $"@end: ret" }; DebugInfo debugInfo; var tokenScript = AssemblerUtils.BuildScript(scriptString, "GenerateToken", out debugInfo, out labels); var sb = ScriptUtils. BeginScript(). AllowGas(signerKeys.Address, Address.Null, MinimumFee, 9999); var triggerMap = new Dictionary <AccountTrigger, int>(); var onMintLabel = AccountTrigger.OnMint.ToString(); if (labels.ContainsKey(onMintLabel)) { triggerMap[AccountTrigger.OnMint] = labels[onMintLabel]; } var methods = AccountContract.GetTriggersForABI(triggerMap); var abi = new ContractInterface(methods, Enumerable.Empty <ContractEvent>()); var abiBytes = abi.ToByteArray(); sb.CallInterop("Nexus.CreateToken", signerKeys.Address, symbol, name, maxSupply, decimals, flags, tokenScript, abiBytes); if (!flags.HasFlag(TokenFlags.Fungible)) { Console.Write("NFT deployment not supported yet"); return(null); } sb.SpendGas(signerKeys.Address); var script = sb.EndScript(); return(script); }