Пример #1
0
        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);
        }
Пример #2
0
        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;
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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]),
                    });
Пример #7
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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }