Example #1
0
        public async Task <object> CreateMultisigWallet(PhantasmaKeys keyPair, MultisigSettings settings)
        {
            try
            {
                var multisigScript = SendUtils.GenerateMultisigScript(settings);

                var script = ScriptUtils.BeginScript()
                             .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                             .CallContract("account", "RegisterScript", keyPair.Address, multisigScript)
                             .SpendGas(keyPair.Address)
                             .EndScript();

                var nexusName = WalletConfig.Network;
                var tx        = new Phantasma.Blockchain.Transaction(nexusName, "main", script, DateTime.UtcNow + TimeSpan.FromMinutes(30), "PHT-0-8-7");

                tx.Sign(keyPair);

                var txResult = await _phantasmaRpcService.SendRawTx.SendRequestAsync(tx.ToByteArray(true).Encode());

                return(txResult);
            }
            catch (RpcResponseException rpcEx)
            {
                Log.Error($"RPC Exception occurred: {rpcEx.RpcError.Message}");
                return(new ErrorRes {
                    error = rpcEx.RpcError.Message
                });
            }
            catch (Exception ex)
            {
                Log.Error($"Exception occurred: {ex.Message}");
                return(new ErrorRes {
                    error = ex.Message
                });
            }
        }
        public void MultiSigReceive2Test()
        {
            var owner = KeyPair.Generate();

            var multiAddr = KeyPair.Generate();
            var signee1   = KeyPair.Generate();
            var signee2   = KeyPair.Generate();
            var signee3   = KeyPair.Generate();
            var signee4   = KeyPair.Generate();

            var target = KeyPair.Generate();

            List <KeyPair> signees = new List <KeyPair>()
            {
                signee1, signee2, signee3
            };

            var simulator = new ChainSimulator(owner, 1234);

            var minSignees = 4;

            List <Address> addressList = new List <Address>()
            {
                multiAddr.Address,
                signee1.Address,
                signee2.Address,
                signee3.Address,
                signee4.Address
            };

            MultisigSettings settings = new MultisigSettings
            {
                addressCount = addressList.Count,
                signeeCount  = minSignees,
                addressArray = addressList.ToArray()
            };

            var script = GenerateMultisigScript(settings);

            simulator.BeginBlock();
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, target.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, target.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee1.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee1.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee2.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee2.Address, simulator.Nexus.RootChain, "SOUL", 2);

            simulator.GenerateTransfer(owner, signee3.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, signee3.Address, simulator.Nexus.RootChain, "SOUL", 2);

            // register script
            simulator.GenerateCustomTransaction(multiAddr,
                                                () => ScriptUtils.BeginScript().AllowGas(multiAddr.Address, Address.Null, 1, 9999)
                                                .CallContract("account", "RegisterScript", multiAddr.Address, script).SpendGas(multiAddr.Address)
                                                .EndScript());
            simulator.EndBlock();

            var balance = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Assert.IsTrue(balance == 2);

            var accountScript = simulator.Nexus.LookUpAddressScript(multiAddr.Address);

            Assert.IsTrue(accountScript != null && accountScript.Length > 0);

            simulator.BeginBlock();

            // send to multisig address
            simulator.GenerateTransfer(target, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee1, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee2, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);
            simulator.GenerateTransfer(signee3, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 1);

            simulator.EndBlock();

            var sourceBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Console.WriteLine("BALANCE: " + sourceBalanceSOUL);
            Assert.IsTrue(sourceBalanceSOUL == 6);

            var targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", target.Address);

            Assert.IsTrue(targetBalanceSOUL == 1);

            targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", signee1.Address);
            Assert.IsTrue(targetBalanceSOUL == 1);

            targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", signee2.Address);
            Assert.IsTrue(targetBalanceSOUL == 1);
        }
        public void MultiSigFail3Test()
        {
            var owner     = KeyPair.Generate();
            var multiAddr = KeyPair.Generate();

            var signee1 = KeyPair.Generate();
            var signee2 = KeyPair.Generate();

            var target = KeyPair.Generate();

            List <KeyPair> signees = new List <KeyPair>()
            {
                signee1, signee2
            };

            var simulator  = new ChainSimulator(owner, 1234);
            var minSignees = 4;

            List <Address> addressList = new List <Address>()
            {
                multiAddr.Address,
                signee1.Address,
                signee2.Address
            };

            MultisigSettings settings = new MultisigSettings
            {
                addressCount = addressList.Count,
                signeeCount  = minSignees,
                addressArray = addressList.ToArray()
            };

            var script = GenerateMultisigScript(settings);

            simulator.BeginBlock();

            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "KCAL", 100000000);
            simulator.GenerateTransfer(owner, multiAddr.Address, simulator.Nexus.RootChain, "SOUL", 2);

            // register script
            simulator.GenerateCustomTransaction(multiAddr,
                                                () => ScriptUtils.BeginScript().AllowGas(multiAddr.Address, Address.Null, 1, 9999)
                                                .CallContract("account", "RegisterScript", multiAddr.Address, script).SpendGas(multiAddr.Address)
                                                .EndScript());
            simulator.EndBlock();

            var balance = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Assert.IsTrue(balance == 2);

            var accountScript = simulator.Nexus.LookUpAddressScript(multiAddr.Address);

            Assert.IsTrue(accountScript != null && accountScript.Length > 0);

            Assert.ThrowsException <Exception>(() =>
            {
                simulator.BeginBlock();
                // do multisig tx --> will fail with Phantasma.VM.VMDebugException: transfer failed
                simulator.GenerateTransfer(multiAddr, target.Address, simulator.Nexus.RootChain, "SOUL", 1, signees);
                simulator.EndBlock();
            });

            var sourceBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", multiAddr.Address);

            Console.WriteLine("SOUL: " + sourceBalanceSOUL);
            Assert.IsTrue(sourceBalanceSOUL == 2);

            var targetBalanceKCAL = simulator.Nexus.RootChain.GetTokenBalance("KCAL", target.Address);

            Assert.IsTrue(targetBalanceKCAL == 0);

            var targetBalanceSOUL = simulator.Nexus.RootChain.GetTokenBalance("SOUL", target.Address);

            Assert.IsTrue(targetBalanceSOUL == 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);
        }
Example #5
0
        public async Task <string> TransferTokensCustomNFT(PhantasmaKeys keyPair, string addressTo, string chainName, string symbol, string amountId, string payload, bool donation, MultisigSettings settings = new MultisigSettings())
        {
            try
            {
                int    decimals     = PhantasmaTokens.SingleOrDefault(t => t.Symbol == symbol).Decimals;
                var    bigIntAmount = UnitConversion.ToBigInteger(decimal.Parse(amountId), decimals);
                byte[] script;

                var    destinationAddress         = Address.FromText(addressTo);
                var    bigIntAmountDonation       = 500000000;
                string symbolDonation             = "SOUL";
                var    destinationAddressDonation = Address.FromText("P2K61GfcUbfWqCur644iLECZ62NAefuKgBkB6FrpMsqYHv6");
                if (donation)
                {
                    script = ScriptUtils.BeginScript()
                             .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                             .TransferTokens(symbol, keyPair.Address, destinationAddress, bigIntAmount)
                             .TransferTokens(symbolDonation, keyPair.Address, destinationAddressDonation, bigIntAmountDonation)
                             .SpendGas(keyPair.Address)
                             .EndScript();
                }
                else
                {
                    script = ScriptUtils.BeginScript()
                             .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                             .TransferTokens(symbol, keyPair.Address, destinationAddress, bigIntAmount)
                             .SpendGas(keyPair.Address)
                             .EndScript();
                }

                var nexusName = WalletConfig.Network;
                var tx        = new Phantasma.Blockchain.Transaction(nexusName, chainName, script,
                                                                     DateTime.UtcNow + TimeSpan.FromMinutes(30), payload);
                tx.Sign(keyPair);

                var txResult = await _phantasmaRpcService.SendRawTx.SendRequestAsync(tx.ToByteArray(true).Encode());

                Log.Information("txResult send: " + txResult);
                return(txResult);
            }
            catch (RpcResponseException rpcEx)
            {
                Log.Information($"RPC Exception occurred: {rpcEx.RpcError.Message}");
                return("");
            }
            catch (Exception ex)
            {
                Log.Information($"Exception occurred: {ex.Message}");
                return("");
            }
        }
Example #6
0
        public async Task <string> TransferTokens(bool isFungible, PhantasmaKeys keyPair, string addressTo, string chainName, string symbol, string amountId, bool isName, MultisigSettings settings = new MultisigSettings())
        {
            try
            {
                int    decimals = PhantasmaTokens.SingleOrDefault(t => t.Symbol == symbol).Decimals;
                byte[] script;
                if (isFungible)
                {
                    var bigIntAmount = UnitConversion.ToBigInteger(decimal.Parse(amountId), decimals);
                    if (NeoWallet.IsValidAddress(addressTo))
                    {
                        var addressNeo = NeoWallet.EncodeAddress(addressTo);
                        Log.Information("Transfer to " + addressNeo);
                        script = ScriptUtils.BeginScript()
                                 .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                                 .TransferTokens(symbol, keyPair.Address, addressNeo, bigIntAmount)
                                 .SpendGas(keyPair.Address)
                                 .EndScript();
                    }
                    else
                    {
                        if (isName)
                        {
                            Log.Information("Transfer to " + addressTo);
                            script = ScriptUtils.BeginScript()
                                     .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                                     .TransferTokens(symbol, keyPair.Address, addressTo, bigIntAmount)
                                     .SpendGas(keyPair.Address)
                                     .EndScript();
                        }
                        else
                        {
                            var destinationAddress = Address.FromText(addressTo);
                            Log.Information("Transfer to " + destinationAddress.Text);
                            script = ScriptUtils.BeginScript()
                                     .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                                     .TransferTokens(symbol, keyPair.Address, destinationAddress, bigIntAmount)
                                     .SpendGas(keyPair.Address)
                                     .EndScript();
                        }
                    }
                }
                else
                {
                    var bigIntAmount = BigInteger.Parse(amountId);
                    if (isName)
                    {
                        Log.Information("Transfer to " + addressTo);
                        script = ScriptUtils.BeginScript()
                                 .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                                 .TransferNFT(symbol, keyPair.Address, addressTo, bigIntAmount)
                                 .SpendGas(keyPair.Address)
                                 .EndScript();
                    }
                    else
                    {
                        var destinationAddress = Address.FromText(addressTo);
                        Log.Information("Transfer to " + destinationAddress.Text);
                        script = ScriptUtils.BeginScript()
                                 .AllowGas(keyPair.Address, Address.Null, MinimumFee, 800)
                                 .TransferNFT(symbol, keyPair.Address, destinationAddress, bigIntAmount)
                                 .SpendGas(keyPair.Address)
                                 .EndScript();
                    }
                }


                var nexusName = WalletConfig.Network;
                var tx        = new Phantasma.Blockchain.Transaction(nexusName, chainName, script,
                                                                     DateTime.UtcNow + TimeSpan.FromMinutes(30), "PHT-0-8-7");
                tx.Sign(keyPair);

                // from here on we need PhantasmaRelay to proceed with a multisig TX
                //
                //if (settings.addressCount != null)
                //{
                //

                //}
                var txResult = await _phantasmaRpcService.SendRawTx.SendRequestAsync(tx.ToByteArray(true).Encode());

                Log.Information("txResult send: " + txResult);
                return(txResult);
            }
            catch (RpcResponseException rpcEx)
            {
                Log.Information($"RPC Exception occurred: {rpcEx.RpcError.Message}");
                return("");
            }
            catch (Exception ex)
            {
                Log.Information($"Exception occurred: {ex.Message}");
                return("");
            }
        }
Example #7
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);
        }