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); }
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(""); } }
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(""); } }
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); }