public IActionResult GetBalance() { try { FederationWallet wallet = this.walletManager.GetWallet(); if (wallet == null) { return(this.NotFound("No federation wallet found.")); } (Money ConfirmedAmount, Money UnConfirmedAmount)result = this.walletManager.GetSpendableAmount(); var balance = new AccountBalanceModel { CoinType = this.coinType, AmountConfirmed = result.ConfirmedAmount, AmountUnconfirmed = result.UnConfirmedAmount, }; var model = new WalletBalanceModel(); model.AccountsBalances.Add(balance); return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
// GET: Client/WalletBalance public ActionResult balanceTransfer() { WalletBalanceModel walletBalance = new WalletBalanceModel(); Dictionary <string, string> PurposeList = _walletUser.GetProposeList(); walletBalance.PurposeList = ApplicationUtilities.SetDDLValue(PurposeList, "", "--Propose--"); return(View(walletBalance)); }
public ActionResult balanceTransfer(WalletBalanceModel walletBalance) { Dictionary <string, string> PurposeList = _walletUser.GetProposeList(); walletBalance.PurposeList = ApplicationUtilities.SetDDLValue(PurposeList, "", "--Propose--"); if ((Convert.ToDecimal(walletBalance.Amount) > 1000 || Convert.ToDecimal(walletBalance.Amount) < 10) && walletBalance.Type == "T") { ModelState.AddModelError("Amount", "Amount should be between 10-1000"); return(View(walletBalance)); } if (walletBalance.Type == "R") { ModelState.Remove(("Propose")); if ((Convert.ToDecimal(walletBalance.Amount) > 1000 || Convert.ToDecimal(walletBalance.Amount) < 10)) { ModelState.AddModelError("Amount", "Amount should be between 10-1000"); return(View(walletBalance)); } } string usertype = Session["UserType"].ToString(); string agentid = Session["AgentId"].ToString(); CommonDbResponse response = _walletUser.CheckMobileNumber(agentid, walletBalance.ReceiverAgentId, usertype, "tb"); if (response.Code != 0) { ModelState.AddModelError("ReceiverAgentId", "Invalid User Detail"); return(View(walletBalance)); } else { ModelState.Remove("ReceiverAgentId"); } if (ModelState.IsValid) { //walletBalance.AgentId = Session["AgentId"].ToString(); walletBalance.ActionUser = Session["UserName"].ToString(); walletBalance.IpAddress = ApplicationUtilities.GetIP(); WalletBalanceCommon walletBalanceCommon = walletBalance.MapObject <WalletBalanceCommon>(); CommonDbResponse dbResponse = _walletUser.WalletBalanceRT(walletBalanceCommon); if (dbResponse.Code == 0) { dbResponse.SetMessageInTempData(this, "balanceTransfer"); return(RedirectToAction("balanceTransfer", ControllerName)); } dbResponse.SetMessageInTempData(this, "balanceTransfer"); return(RedirectToAction("balanceTransfer")); } else { return(View(walletBalance)); } return(RedirectToAction("balanceTransfer")); }
public void GetBalance() { this.fedWallet.MultiSigAddress = new MultiSigAddress(); IActionResult result = this.controller.GetBalance(); WalletBalanceModel model = this.ActionResultToModel <WalletBalanceModel>(result); Assert.Single(model.AccountsBalances); Assert.Equal(CoinType.Stratis, model.AccountsBalances.First().CoinType); Assert.Equal(0, model.AccountsBalances.First().AmountConfirmed.Satoshi); }
public IActionResult GetBalance([FromQuery] WalletBalanceRequest request) { // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletBalanceModel model = new WalletBalanceModel { AccountsBalances = new List <AccountBalance>() }; var accounts = this.walletManager.GetAccountsByCoinType(request.WalletName, this.coinType).ToList(); foreach (var account in accounts) { var allTransactions = account.ExternalAddresses.SelectMany(a => a.Transactions) .Concat(account.InternalAddresses.SelectMany(i => i.Transactions)).ToList(); AccountBalance balance = new AccountBalance { CoinType = this.coinType, Name = account.Name, HdPath = account.HdPath, AmountConfirmed = allTransactions.Sum(t => t.SpendableAmount(true)), AmountUnconfirmed = allTransactions.Sum(t => t.SpendableAmount(false)), }; model.AccountsBalances.Add(balance); } return(this.Json(model)); } catch (Exception e) { return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public IActionResult GetBalance([FromQuery] WalletBalanceRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid if (!this.ModelState.IsValid) { var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors))); } try { WalletBalanceModel model = new WalletBalanceModel(); var accounts = this.walletManager.GetAccounts(request.WalletName).ToList(); foreach (var account in accounts) { var result = account.GetSpendableAmount(); AccountBalance balance = new AccountBalance { CoinType = this.coinType, Name = account.Name, HdPath = account.HdPath, AmountConfirmed = result.ConfirmedAmount, AmountUnconfirmed = result.UnConfirmedAmount, }; model.AccountsBalances.Add(balance); } return(this.Json(model)); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString())); } }
public async Task GetHistoryFromMiningNode() { using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a mining node. CoreNode miningNode = builder.CreateStratisPosNode(this.network).WithWallet().Start(); TestHelper.MineBlocks(miningNode, 5); // Check balances. WalletBalanceModel sendingNodeBalances = await $"http://localhost:{miningNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(98000000 + (4 * 4), MoneyUnit.BTC)); // Act. WalletHistoryModel firstAccountHistory = await $"http://localhost:{miningNode.ApiPort}/api" .AppendPathSegment("wallet/history") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0" }) .GetJsonAsync <WalletHistoryModel>(); // Assert. firstAccountHistory.AccountsHistoryModel.Should().NotBeEmpty(); ICollection <TransactionItemModel> history = firstAccountHistory.AccountsHistoryModel.First().TransactionsHistory; history.Should().NotBeEmpty(); history.Count.Should().Be(5); TransactionItemModel firstItem = history.First(); // First item in the list but last item to have occurred. firstItem.Amount.Should().Be(new Money(4, MoneyUnit.BTC)); firstItem.BlockIndex.Should().Be(0); firstItem.ConfirmedInBlock.Should().Be(5); firstItem.ToAddress.Should().NotBeNullOrEmpty(); firstItem.Fee.Should().BeNull(); } }
public async Task GetBalancesAsync() { int sendingAccountBalanceOnStart = 98000596; int receivingAccountBalanceOnStart = 0; using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a sending and a receiving node. CoreNode node1 = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest10Miner).Start(); // Act. WalletBalanceModel node1Balances = await $"http://localhost:{node1.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); // Assert. AccountBalanceModel node1Balance = node1Balances.AccountsBalances.Single(); node1Balance.AmountConfirmed.Should().Be(new Money(98000036, MoneyUnit.BTC)); // premine is 98M + 9 blocks * 4. node1Balance.AmountUnconfirmed.Should().Be(Money.Zero); node1Balance.SpendableAmount.Should().Be(Money.Zero); // Maturity for StratisregTest is 10, so at block 10, no coin is spendable. // Arrange. // Create a sending and a receiving node. CoreNode node2 = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest100Miner).Start(); // Act. WalletBalanceModel node2Balances = await $"http://localhost:{node2.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); // Assert. AccountBalanceModel node2Balance = node2Balances.AccountsBalances.Single(); node2Balance.AmountConfirmed.Should().Be(new Money(98000396, MoneyUnit.BTC)); // premine is 98M + 99 blocks * 4. node2Balance.AmountUnconfirmed.Should().Be(Money.Zero); node2Balance.SpendableAmount.Should().Be(new Money(98000396 - 40, MoneyUnit.BTC)); // Maturity for StratisregTest is 10, so at block 100, the coins in the last 10 blocks (10*4) are not spendable. } }
/// <summary> /// Gets the balance of a wallet. /// </summary> /// <param name="request">The request parameters.</param> /// <returns></returns> public WalletBalanceModel GetBalance(WalletBalanceRequest request) { Guard.NotNull(request, nameof(request)); // checks the request is valid //if (!this.ModelState.IsValid) //{ // return BuildErrorResponse(this.ModelState); //} try { WalletBalanceModel model = new WalletBalanceModel(); IEnumerable <AccountBalance> balances = this.walletManager.GetBalances(request.WalletName, request.AccountName); foreach (AccountBalance balance in balances) { HdAccount account = balance.Account; model.AccountsBalances.Add(new AccountBalanceModel { CoinType = this.coinType, Name = account.Name, HdPath = account.HdPath, AmountConfirmed = balance.AmountConfirmed, AmountUnconfirmed = balance.AmountUnconfirmed }); } return(model); } catch (Exception e) { this.logger.LogError("Exception occurred: {0}", e.ToString()); //return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); throw; } }
public async Task SendingATransactionWithAnOpReturn() { int sendingAccountBalanceOnStart = 98000596; int receivingAccountBalanceOnStart = 0; using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a sending and a receiving node. CoreNode sendingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Miner).Start(); CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Listener).Start(); TestHelper.ConnectAndSync(sendingNode, receivingNode); // Check balances. WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC)); WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart)); // Act. // Get an address to send to. IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 }) .GetJsonAsync <IEnumerable <string> >(); // Build and send the transaction with an Op_Return. WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/build-transaction") .PostJsonAsync(new BuildTransactionRequest { WalletName = "mywallet", AccountName = "account 0", FeeType = "low", Password = "******", ShuffleOutputs = true, AllowUnconfirmed = true, Recipients = unusedaddresses.Select(address => new RecipientModel { DestinationAddress = address, Amount = "1" }).ToList(), OpReturnData = "some data to send", OpReturnAmount = "1" }) .ReceiveJson <WalletBuildTransactionModel>(); await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/send-transaction") .PostJsonAsync(new SendTransactionRequest { Hex = buildTransactionModel.Hex }) .ReceiveJson <WalletSendTransactionModel>(); // Assert. // Mine and sync so that we make sure the receiving node is up to date. TestHelper.MineBlocks(sendingNode, 1); TestHelper.WaitForNodeToSync(sendingNode, receivingNode); // The receiving node should have coins. receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed).Should().Be(new Money(receivingAccountBalanceOnStart + 1, MoneyUnit.BTC)); // The sending node should have fewer coins. sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed).Should().Be(new Money(sendingAccountBalanceOnStart + 4 - 2, MoneyUnit.BTC)); // Check the transaction. string lastBlockHash = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("consensus/getbestblockhash") .GetJsonAsync <string>(); BlockTransactionDetailsModel block = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("blockstore/block") .SetQueryParams(new { hash = lastBlockHash, showTransactionDetails = true, outputJson = true }) .GetJsonAsync <BlockTransactionDetailsModel>(); TransactionVerboseModel trx = block.Transactions.SingleOrDefault(t => t.TxId == buildTransactionModel.TransactionId.ToString()); trx.Should().NotBeNull(); Vout opReturnOutputFromBlock = trx.VOut.Single(t => t.ScriptPubKey.Type == "nulldata"); opReturnOutputFromBlock.Value.Should().Be(1); var script = opReturnOutputFromBlock.ScriptPubKey.Asm; string[] ops = script.Split(" "); ops[0].Should().Be("OP_RETURN"); Encoders.Hex.DecodeData(ops[1]).Should().BeEquivalentTo(System.Text.Encoding.UTF8.GetBytes("some data to send")); } }
public async Task SendingFromManyAddressesToOneAddress() { int sendingAccountBalanceOnStart = 98000596; int receivingAccountBalanceOnStart = 0; using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a sending and a receiving node. CoreNode sendingNode = builder.CreateStratisPosNode(this.network).WithWallet().Start(); CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithWallet().Start(); // Mine a few blocks to fund the sending node and connect the nodes. IEnumerable <string> addressesToFund = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 150 }) .GetJsonAsync <IEnumerable <string> >(); foreach (string address in addressesToFund) { TestHelper.MineBlocks(sendingNode, 1, syncNode: false, miningAddress: address); } TestHelper.ConnectAndSync(sendingNode, receivingNode); // Check balances. WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC)); WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart)); // Check max spendable amount. var maxBalanceResponse = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/maxbalance") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", feetype = "low", allowunconfirmed = true }) .GetJsonAsync <MaxSpendableAmountModel>(); Money totalToSpend = maxBalanceResponse.MaxSpendableAmount + maxBalanceResponse.Fee; // Act. // Get an address to send to. IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 1 }) .GetJsonAsync <IEnumerable <string> >(); // Build and send the transaction with 50 recipients. WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/build-transaction") .PostJsonAsync(new BuildTransactionRequest { WalletName = "mywallet", AccountName = "account 0", FeeAmount = maxBalanceResponse.Fee.ToString(), Password = "******", ShuffleOutputs = true, AllowUnconfirmed = true, Recipients = unusedaddresses.Select(address => new RecipientModel { DestinationAddress = address, Amount = maxBalanceResponse.MaxSpendableAmount.ToString() }).ToList() }) .ReceiveJson <WalletBuildTransactionModel>(); await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/send-transaction") .PostJsonAsync(new SendTransactionRequest { Hex = buildTransactionModel.Hex }) .ReceiveJson <WalletSendTransactionModel>(); // Assert. // The sending node should have 50 (+ fee) fewer coins. sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC) - totalToSpend); // Mine and sync so that we make sure the receiving node is up to date. TestHelper.MineBlocks(sendingNode, 1); TestHelper.WaitForNodeToSync(sendingNode, receivingNode); // The receiving node should have 50 more coins. receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart) + maxBalanceResponse.MaxSpendableAmount); } }
public async Task SendingFromOneAddressToFiftyAddresses() { int sendingAccountBalanceOnStart = 98000596; int receivingAccountBalanceOnStart = 0; using (NodeBuilder builder = NodeBuilder.Create(this)) { // Arrange. // Create a sending and a receiving node. CoreNode sendingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Miner).Start(); CoreNode receivingNode = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StratisRegTest150Listener).Start(); TestHelper.ConnectAndSync(sendingNode, receivingNode); // Check balances. WalletBalanceModel sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart, MoneyUnit.BTC)); WalletBalanceModel receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); AccountBalanceModel receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart)); // Act. // Get 50 addresses to send to. IEnumerable <string> unusedaddresses = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/unusedAddresses") .SetQueryParams(new { walletName = "mywallet", accountName = "account 0", count = 50 }) .GetJsonAsync <IEnumerable <string> >(); // Build and send the transaction with 50 recipients. WalletBuildTransactionModel buildTransactionModel = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/build-transaction") .PostJsonAsync(new BuildTransactionRequest { WalletName = "mywallet", AccountName = "account 0", FeeType = "low", Password = "******", ShuffleOutputs = true, AllowUnconfirmed = true, Recipients = unusedaddresses.Select(address => new RecipientModel { DestinationAddress = address, Amount = "1" }).ToList() }) .ReceiveJson <WalletBuildTransactionModel>(); await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/send-transaction") .PostJsonAsync(new SendTransactionRequest { Hex = buildTransactionModel.Hex }) .ReceiveJson <WalletSendTransactionModel>(); // Assert. // The sending node should have 50 (+ fee) fewer coins. sendingNodeBalances = await $"http://localhost:{sendingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); sendingAccountBalance = sendingNodeBalances.AccountsBalances.Single(); (sendingAccountBalance.AmountConfirmed + sendingAccountBalance.AmountUnconfirmed).Should().Be(new Money(sendingAccountBalanceOnStart - 50 - buildTransactionModel.Fee.ToDecimal(MoneyUnit.BTC), MoneyUnit.BTC)); // Mine and sync so that we make sure the receiving node is up to date. TestHelper.MineBlocks(sendingNode, 1); // The receiving node should have 50 more coins. receivingNodeBalances = await $"http://localhost:{receivingNode.ApiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(new { walletName = "mywallet" }) .GetJsonAsync <WalletBalanceModel>(); receivingAccountBalance = receivingNodeBalances.AccountsBalances.Single(); (receivingAccountBalance.AmountConfirmed + receivingAccountBalance.AmountUnconfirmed).Should().Be(new Money(receivingAccountBalanceOnStart + 50, MoneyUnit.BTC)); } }
/// <inheritdoc /> public async Task TumbleAsync(string originWalletName, string destinationWalletName, string originWalletPassword) { // Make sure it won't start new tumbling round if already started if (this.State == TumbleState.Tumbling) { this.logger.LogDebug("Tumbler is already running"); throw new Exception("Tumbling is already running"); } this.tumblingState.TumblerUri = new Uri(this.TumblerAddress); // Check if in initial block download if (!this.chain.IsDownloaded()) { this.logger.LogDebug("Chain is still being downloaded: " + this.chain.Tip); throw new Exception("Chain is still being downloaded"); } Wallet destinationWallet = this.walletManager.GetWallet(destinationWalletName); Wallet originWallet = this.walletManager.GetWallet(originWalletName); // Check if origin wallet has a balance WalletBalanceModel model = new WalletBalanceModel(); var originWalletAccounts = this.walletManager.GetAccounts(originWallet.Name).ToList(); var originConfirmed = new Money(0); var originUnconfirmed = new Money(0); foreach (var originAccount in originWallet.GetAccountsByCoinType(this.tumblingState.CoinType)) { var result = originAccount.GetSpendableAmount(); originConfirmed += result.ConfirmedAmount; originUnconfirmed += result.UnConfirmedAmount; } // Should ideally take network transaction fee into account too, but that is dynamic if ((originConfirmed + originUnconfirmed) <= (this.TumblerParameters.Denomination + this.TumblerParameters.Fee)) { this.logger.LogDebug("Insufficient funds in origin wallet"); throw new Exception("Insufficient funds in origin wallet"); } // TODO: Check if password is valid before starting any cycles // Update the state and save this.tumblingState.DestinationWallet = destinationWallet ?? throw new Exception($"Destination wallet not found. Have you created a wallet with name {destinationWalletName}?"); this.tumblingState.DestinationWalletName = destinationWalletName; this.tumblingState.OriginWallet = originWallet ?? throw new Exception($"Origin wallet not found. Have you created a wallet with name {originWalletName}?"); this.tumblingState.OriginWalletName = originWalletName; this.tumblingState.OriginWalletPassword = originWalletPassword; var accounts = this.tumblingState.DestinationWallet.GetAccountsByCoinType(this.tumblingState.CoinType); // TODO: Possibly need to preserve destination account name in tumbling state. Default to first account for now string accountName = null; foreach (var account in accounts) { if (account.Index == 0) { accountName = account.Name; } } var destAccount = this.tumblingState.DestinationWallet.GetAccountByCoinType(accountName, this.tumblingState.CoinType); var key = destAccount.ExtendedPubKey; var keyPath = new KeyPath("0"); // Stop and dispose onlymonitor if (this.broadcasterJob != null && this.broadcasterJob.Started) { await this.broadcasterJob.Stop().ConfigureAwait(false); } this.runtime?.Dispose(); // Bypass Tor for integration tests FullNodeTumblerClientConfiguration config; if (this.TumblerAddress.Contains("127.0.0.1")) { config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false, connectionTest: false, useProxy: false); } else { config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false, connectionTest: false, useProxy: true); } this.runtime = await TumblerClientRuntime.FromConfigurationAsync(config).ConfigureAwait(false); var extPubKey = new BitcoinExtPubKey(key, this.runtime.Network); if (key != null) { this.runtime.DestinationWallet = new ClientDestinationWallet(extPubKey, keyPath, this.runtime.Repository, this.runtime.Network); } this.TumblerParameters = this.runtime.TumblerParameters; // Run onlymonitor mode this.broadcasterJob = this.runtime.CreateBroadcasterJob(); this.broadcasterJob.Start(); // Run tumbling mode this.stateMachine = new StateMachinesExecutor(this.runtime); this.stateMachine.Start(); this.State = TumbleState.Tumbling; return; }
private async Task <bool> CheckWalletRequirementsAsync(NodeType nodeType, int apiPort) { var chainName = nodeType == NodeType.MainChain ? "STRAX" : "CIRRUS"; var amountToCheck = nodeType == NodeType.MainChain ? CollateralRequirement : FeeRequirement; var chainTicker = nodeType == NodeType.MainChain ? this.mainchainNetwork.CoinTicker : this.sidechainNetwork.CoinTicker; Console.WriteLine($"Please enter the name of the {chainName} wallet that contains the required collateral of {amountToCheck} {chainTicker}:"); var walletName = Console.ReadLine(); WalletInfoModel walletInfoModel = await $"http://localhost:{apiPort}/api".AppendPathSegment("Wallet/list-wallets").GetJsonAsync <WalletInfoModel>(); if (walletInfoModel.WalletNames.Contains(walletName)) { Console.WriteLine($"SUCCESS: Wallet with name '{chainName}' found."); } else { Console.WriteLine($"{chainName} wallet with name '{walletName}' does not exist."); ConsoleKeyInfo key; do { Console.WriteLine($"Would you like to restore you {chainName} wallet that holds the required amount of {amountToCheck} {chainTicker} now? Enter (Y) to continue or (N) to exit."); key = Console.ReadKey(); if (key.Key == ConsoleKey.Y || key.Key == ConsoleKey.N) { break; } } while (true); if (key.Key == ConsoleKey.N) { Console.WriteLine($"You have chosen to exit the registration script."); return(false); } if (!await RestoreWalletAsync(apiPort, chainName, walletName)) { return(false); } } // Check wallet height (sync) status. do { var walletNameRequest = new WalletName() { Name = walletName }; WalletGeneralInfoModel walletInfo = await $"http://localhost:{apiPort}/api".AppendPathSegment("wallet/general-info").SetQueryParams(walletNameRequest).GetJsonAsync <WalletGeneralInfoModel>(); StatusModel blockModel = await $"http://localhost:{apiPort}/api".AppendPathSegment("node/status").GetJsonAsync <StatusModel>(); if (walletInfo.LastBlockSyncedHeight > (blockModel.ConsensusHeight - 50)) { Console.WriteLine($"{chainName} wallet is synced."); break; } Console.WriteLine($"Syncing {chainName} wallet, current height {walletInfo.LastBlockSyncedHeight}..."); await Task.Delay(TimeSpan.FromSeconds(3)); } while (true); // Check wallet balance. try { var walletBalanceRequest = new WalletBalanceRequest() { WalletName = walletName }; WalletBalanceModel walletBalanceModel = await $"http://localhost:{apiPort}/api" .AppendPathSegment("wallet/balance") .SetQueryParams(walletBalanceRequest) .GetJsonAsync <WalletBalanceModel>(); if (walletBalanceModel.AccountsBalances[0].SpendableAmount / 100000000 > amountToCheck) { Console.WriteLine($"SUCCESS: The {chainName} wallet contains the required amount of {amountToCheck} {chainTicker}."); return(true); } Console.WriteLine($"ERROR: The {chainName} wallet does not contain the required amount of {amountToCheck} {chainTicker}."); } catch (Exception ex) { Console.WriteLine($"ERROR: An exception occurred trying to check the wallet balance: {ex}"); } return(false); }