public async Task ElementsAssetsAreHandledCorrectly() { using (var tester = ServerTester.Create()) { tester.ActivateLBTC(); await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("LBTC"); user.RegisterDerivationScheme("USDT"); //no tether on our regtest, lets create it and set it var tether = tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("USDT"); var lbtc = tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("LBTC"); var issueAssetResult = await tester.LBTCExplorerNode.SendCommandAsync("issueasset", 100000, 0); tether.AssetId = uint256.Parse(issueAssetResult.Result["asset"].ToString()); ((ElementsBTCPayNetwork)tester.PayTester.GetService <BTCPayWalletProvider>().GetWallet("USDT").Network) .AssetId = tether.AssetId; Logs.Tester.LogInformation($"Asset is {tether.AssetId}"); Assert.Equal(tether.AssetId, tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("USDT").AssetId); Assert.Equal(tether.AssetId, ((ElementsBTCPayNetwork)tester.PayTester.GetService <BTCPayWalletProvider>().GetWallet("USDT").Network).AssetId); //test: register 2 assets on the same elements network and make sure paying an invoice on one does not affect the other in any way var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC")); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count); var ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC")); //1 lbtc = 1 btc Assert.Equal(1, ci.Rate); var star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true, 1, "UNSET", lbtc.AssetId); TestUtils.Eventually(() => { var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); Assert.Equal("paid", localInvoice.Status); Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC")).Payments); }); invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC")); ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT")); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count); star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true, 1, "UNSET", tether.AssetId); TestUtils.Eventually(() => { var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); Assert.Equal("paid", localInvoice.Status); Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)).Payments); }); } }
public async Task CanUseJSModal() { using (var s = SeleniumTester.Create()) { await s.StartAsync(); s.GoToRegister(); s.RegisterNewUser(); var store = s.CreateNewStore(); s.GoToStore(store.storeId); s.AddDerivationScheme(); var invoiceId = s.CreateInvoice(store.storeId, 0.001m, "BTC", "*****@*****.**"); var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId); s.Driver.Navigate() .GoToUrl(new Uri(s.Server.PayTester.ServerUri, $"tests/index.html?invoice={invoiceId}")); TestUtils.Eventually(() => { Assert.True(s.Driver.FindElement(By.Name("btcpay")).Displayed); }); await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(invoice .GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike)) .GetPaymentMethodDetails().GetPaymentDestination(), Network.RegTest), new Money(0.001m, MoneyUnit.BTC)); IWebElement closebutton = null; TestUtils.Eventually(() => { var frameElement = s.Driver.FindElement(By.Name("btcpay")); var iframe = s.Driver.SwitchTo().Frame(frameElement); closebutton = iframe.FindElement(By.ClassName("close-action")); Assert.True(closebutton.Displayed); }); closebutton.Click(); s.Driver.AssertElementNotFound(By.Name("btcpay")); Assert.Equal(s.Driver.Url, new Uri(s.Server.PayTester.ServerUri, $"tests/index.html?invoice={invoiceId}").ToString()); } }
public async Task CanUsePullPaymentsViaUI() { using (var s = SeleniumTester.Create()) { await s.StartAsync(); s.RegisterNewUser(true); var receiver = s.CreateNewStore(); var receiverSeed = s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit); await s.Server.ExplorerNode.GenerateAsync(1); await s.FundStoreWallet(denomination : 50.0m); s.GoToWallet(navPages: WalletsNavPages.PullPayments); s.Driver.FindElement(By.Id("NewPullPayment")).Click(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0" + Keys.Enter); s.Driver.FindElement(By.LinkText("View")).Click(); Thread.Sleep(1000); s.GoToWallet(navPages: WalletsNavPages.PullPayments); s.Driver.FindElement(By.Id("NewPullPayment")).Click(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP2"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("100.0" + Keys.Enter); // This should select the first View, ie, the last one PP2 s.Driver.FindElement(By.LinkText("View")).Click(); Thread.Sleep(1000); var address = await s.Server.ExplorerNode.GetNewAddressAsync(); s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString()); s.Driver.FindElement(By.Id("ClaimedAmount")).Clear(); s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("15" + Keys.Enter); s.AssertHappyMessage(); // We should not be able to use an address already used s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString()); s.Driver.FindElement(By.Id("ClaimedAmount")).Clear(); s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("20" + Keys.Enter); s.AssertHappyMessage(StatusMessageModel.StatusSeverity.Error); address = await s.Server.ExplorerNode.GetNewAddressAsync(); s.Driver.FindElement(By.Id("Destination")).Clear(); s.Driver.FindElement(By.Id("Destination")).SendKeys(address.ToString()); s.Driver.FindElement(By.Id("ClaimedAmount")).Clear(); s.Driver.FindElement(By.Id("ClaimedAmount")).SendKeys("20" + Keys.Enter); s.AssertHappyMessage(); Assert.Contains("AwaitingApproval", s.Driver.PageSource); var viewPullPaymentUrl = s.Driver.Url; // This one should have nothing s.GoToWallet(navPages: WalletsNavPages.PullPayments); var payouts = s.Driver.FindElements(By.ClassName("pp-payout")); Assert.Equal(2, payouts.Count); payouts[1].Click(); Assert.Contains("No payout waiting for approval", s.Driver.PageSource); // PP2 should have payouts s.GoToWallet(navPages: WalletsNavPages.PullPayments); payouts = s.Driver.FindElements(By.ClassName("pp-payout")); payouts[0].Click(); Assert.DoesNotContain("No payout waiting for approval", s.Driver.PageSource); s.Driver.FindElement(By.Id("selectAllCheckbox")).Click(); s.Driver.FindElement(By.Id("payCommand")).Click(); s.Driver.ScrollTo(By.Id("SendMenu")); s.Driver.FindElement(By.Id("SendMenu")).ForceClick(); s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).ForceClick(); s.AssertHappyMessage(); TestUtils.Eventually(() => { s.Driver.Navigate().Refresh(); Assert.Contains("badge transactionLabel", s.Driver.PageSource); }); Assert.Equal("payout", s.Driver.FindElement(By.ClassName("transactionLabel")).Text); s.GoToWallet(navPages: WalletsNavPages.Payouts); TestUtils.Eventually(() => { s.Driver.Navigate().Refresh(); Assert.Contains("No payout waiting for approval", s.Driver.PageSource); }); var txs = s.Driver.FindElements(By.ClassName("transaction-link")); Assert.Equal(2, txs.Count); s.Driver.Navigate().GoToUrl(viewPullPaymentUrl); txs = s.Driver.FindElements(By.ClassName("transaction-link")); Assert.Equal(2, txs.Count); Assert.Contains("InProgress", s.Driver.PageSource); await s.Server.ExplorerNode.GenerateAsync(1); TestUtils.Eventually(() => { s.Driver.Navigate().Refresh(); Assert.Contains("Completed", s.Driver.PageSource); }); await s.Server.ExplorerNode.GenerateAsync(10); var pullPaymentId = viewPullPaymentUrl.Split('/').Last(); await TestUtils.EventuallyAsync(async() => { using var ctx = s.Server.PayTester.GetService <ApplicationDbContextFactory>().CreateContext(); var payoutsData = await ctx.Payouts.Where(p => p.PullPaymentDataId == pullPaymentId).ToListAsync(); Assert.True(payoutsData.All(p => p.State == Data.PayoutState.Completed)); }); } }
public async Task ElementsAssetsAreHandledCorrectly() { using (var tester = CreateServerTester()) { tester.ActivateLBTC(); await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("LBTC"); user.RegisterDerivationScheme("USDT"); user.RegisterDerivationScheme("ETB"); await tester.LBTCExplorerNode.GenerateAsync(4); //no tether on our regtest, lets create it and set it var tether = tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("USDT"); var lbtc = tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("LBTC"); var etb = tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("ETB"); var issueAssetResult = await tester.LBTCExplorerNode.SendCommandAsync("issueasset", 100000, 0); tether.AssetId = uint256.Parse(issueAssetResult.Result["asset"].ToString()); ((ElementsBTCPayNetwork)tester.PayTester.GetService <BTCPayWalletProvider>().GetWallet("USDT").Network) .AssetId = tether.AssetId; Assert.Equal(tether.AssetId, tester.NetworkProvider.GetNetwork <ElementsBTCPayNetwork>("USDT").AssetId); Assert.Equal(tether.AssetId, ((ElementsBTCPayNetwork)tester.PayTester.GetService <BTCPayWalletProvider>().GetWallet("USDT").Network).AssetId); var issueAssetResult2 = await tester.LBTCExplorerNode.SendCommandAsync("issueasset", 100000, 0); etb.AssetId = uint256.Parse(issueAssetResult2.Result["asset"].ToString()); ((ElementsBTCPayNetwork)tester.PayTester.GetService <BTCPayWalletProvider>().GetWallet("ETB").Network) .AssetId = etb.AssetId; //test: register 2 assets on the same elements network and make sure paying an invoice on one does not affect the other in any way var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC")); Assert.Equal(3, invoice.SupportedTransactionCurrencies.Count); var ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC")); //1 lbtc = 1 btc Assert.Equal(1, ci.Rate); var star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true, 1, "UNSET", lbtc.AssetId); TestUtils.Eventually(() => { var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); Assert.Equal("paid", localInvoice.Status); Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC")).Payments); }); invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC")); ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT")); Assert.Equal(3, invoice.SupportedTransactionCurrencies.Count); star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true, 1, "UNSET", tether.AssetId); TestUtils.Eventually(() => { var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); Assert.Equal("paid", localInvoice.Status); Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)).Payments); }); //test precision based on https://github.com/ElementsProject/elements/issues/805#issuecomment-601277606 var etbBip21 = new BitcoinUrlBuilder(invoice.CryptoInfo.Single(info => info.CryptoCode == "ETB").PaymentUrls.BIP21, etb.NBitcoinNetwork); //precision = 2, 1ETB = 0.00000100 Assert.Equal(100, etbBip21.Amount.Satoshi); var lbtcBip21 = new BitcoinUrlBuilder(invoice.CryptoInfo.Single(info => info.CryptoCode == "LBTC").PaymentUrls.BIP21, lbtc.NBitcoinNetwork); //precision = 8, 0.1 = 0.1 Assert.Equal(0.1m, lbtcBip21.Amount.ToDecimal(MoneyUnit.BTC)); } }
public async Task CanPayWithTwoCurrencies() { using (var tester = CreateServerTester()) { tester.ActivateLTC(); await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); // First we try payment with a merchant having only BTC var invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); var cashCow = tester.ExplorerNode; cashCow.Generate(2); // get some money in case var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); var firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.True(invoice.BtcPaid == firstPayment); }); Assert.Single(invoice.CryptoInfo); // Only BTC should be presented var controller = tester.PayTester.GetController <UIInvoiceController>(null); var checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null) .GetAwaiter().GetResult()).Value; Assert.Single(checkout.AvailableCryptos); Assert.Equal("BTC", checkout.CryptoCode); Assert.Single(invoice.PaymentCodes); Assert.Single(invoice.SupportedTransactionCurrencies); Assert.Single(invoice.SupportedTransactionCurrencies); Assert.Single(invoice.PaymentSubtotals); Assert.Single(invoice.PaymentTotals); Assert.True(invoice.PaymentCodes.ContainsKey("BTC")); Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("BTC")); Assert.True(invoice.SupportedTransactionCurrencies["BTC"].Enabled); Assert.True(invoice.PaymentSubtotals.ContainsKey("BTC")); Assert.True(invoice.PaymentTotals.ContainsKey("BTC")); ////////////////////// // Retry now with LTC enabled user.RegisterDerivationScheme("LTC"); invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); cashCow = tester.ExplorerNode; invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); TestLogs.LogInformation("First payment sent to " + invoiceAddress); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.True(invoice.BtcPaid == firstPayment); }); cashCow = tester.LTCExplorerNode; var ltcCryptoInfo = invoice.CryptoInfo.FirstOrDefault(c => c.CryptoCode == "LTC"); Assert.NotNull(ltcCryptoInfo); invoiceAddress = BitcoinAddress.Create(ltcCryptoInfo.Address, cashCow.Network); var secondPayment = Money.Coins(decimal.Parse(ltcCryptoInfo.Due, CultureInfo.InvariantCulture)); cashCow.Generate(4); // LTC is not worth a lot, so just to make sure we have money... cashCow.SendToAddress(invoiceAddress, secondPayment); TestLogs.LogInformation("Second payment sent to " + invoiceAddress); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal(Money.Zero, invoice.BtcDue); var ltcPaid = invoice.CryptoInfo.First(c => c.CryptoCode == "LTC"); Assert.Equal(Money.Zero, ltcPaid.Due); Assert.Equal(secondPayment, ltcPaid.CryptoPaid); Assert.Equal("paid", invoice.Status); Assert.False((bool)((JValue)invoice.ExceptionStatus).Value); }); controller = tester.PayTester.GetController <UIInvoiceController>(null); checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, "LTC") .GetAwaiter().GetResult()).Value; Assert.Equal(2, checkout.AvailableCryptos.Count); Assert.Equal("LTC", checkout.CryptoCode); Assert.Equal(2, invoice.PaymentCodes.Count()); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count()); Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count()); Assert.Equal(2, invoice.PaymentSubtotals.Count()); Assert.Equal(2, invoice.PaymentTotals.Count()); Assert.True(invoice.PaymentCodes.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled); Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC")); Assert.True(invoice.PaymentTotals.ContainsKey("LTC")); // Check if we can disable LTC invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 5000.0m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true, SupportedTransactionCurrencies = new Dictionary <string, InvoiceSupportedTransactionCurrency>() { { "BTC", new InvoiceSupportedTransactionCurrency() { Enabled = true } } } }, Facade.Merchant); Assert.Single(invoice.CryptoInfo.Where(c => c.CryptoCode == "BTC")); Assert.Empty(invoice.CryptoInfo.Where(c => c.CryptoCode == "LTC")); } }
public async Task CanSetupWallet() { using (var tester = CreateServerTester()) { tester.ActivateLTC(); tester.ActivateLightning(); await tester.StartAsync(); var user = tester.NewAccount(); var cryptoCode = "BTC"; await user.GrantAccessAsync(true); user.RegisterDerivationScheme(cryptoCode); user.RegisterDerivationScheme("LTC"); user.RegisterLightningNode(cryptoCode, LightningConnectionType.CLightning); var btcNetwork = tester.PayTester.Networks.GetNetwork <BTCPayNetwork>(cryptoCode); var invoice = await user.BitPay.CreateInvoiceAsync( new Invoice { Price = 1.5m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); Assert.Equal(3, invoice.CryptoInfo.Length); // Setup Lightning var controller = user.GetController <UIStoresController>(); var lightningVm = (LightningNodeViewModel)Assert.IsType <ViewResult>(await controller.SetupLightningNode(user.StoreId, cryptoCode)).Model; Assert.True(lightningVm.Enabled); var response = await controller.SetLightningNodeEnabled(user.StoreId, cryptoCode, false); Assert.IsType <RedirectToActionResult>(response); // Get enabled state from settings LightningSettingsViewModel lnSettingsModel; response = controller.LightningSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult(); lnSettingsModel = (LightningSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.NotNull(lnSettingsModel?.ConnectionString); Assert.False(lnSettingsModel.Enabled); // Setup wallet WalletSetupViewModel setupVm; var storeId = user.StoreId; response = await controller.GenerateWallet(storeId, cryptoCode, WalletSetupMethod.GenerateOptions, new WalletSetupRequest()); Assert.IsType <ViewResult>(response); // Get enabled state from settings response = controller.WalletSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult(); var onchainSettingsModel = (WalletSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.NotNull(onchainSettingsModel?.DerivationScheme); Assert.True(onchainSettingsModel.Enabled); // Disable wallet onchainSettingsModel.Enabled = false; response = controller.UpdateWalletSettings(onchainSettingsModel).GetAwaiter().GetResult(); Assert.IsType <RedirectToActionResult>(response); response = controller.WalletSettings(user.StoreId, cryptoCode).GetAwaiter().GetResult(); onchainSettingsModel = (WalletSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.NotNull(onchainSettingsModel?.DerivationScheme); Assert.False(onchainSettingsModel.Enabled); var oldScheme = onchainSettingsModel.DerivationScheme; invoice = await user.BitPay.CreateInvoiceAsync( new Invoice { Price = 1.5m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); Assert.Single(invoice.CryptoInfo); Assert.Equal("LTC", invoice.CryptoInfo[0].CryptoCode); // Removing the derivation scheme, should redirect to store page response = controller.ConfirmDeleteWallet(user.StoreId, cryptoCode).GetAwaiter().GetResult(); Assert.IsType <RedirectToActionResult>(response); // Setting it again should show the confirmation page response = await controller.UpdateWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode, DerivationScheme = oldScheme }); setupVm = (WalletSetupViewModel)Assert.IsType <ViewResult>(response).Model; Assert.True(setupVm.Confirmation); // The following part posts a wallet update, confirms it and checks the result // cobo vault file var content = "{\"ExtPubKey\":\"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\"MasterFingerprint\":\"7a7563b5\",\"DerivationPath\":\"M\\/84'\\/0'\\/0'\",\"CoboVaultFirmwareVersion\":\"1.2.0(BTC-Only)\"}"; response = await controller.UpdateWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("cobovault.json", content) }); setupVm = (WalletSetupViewModel)Assert.IsType <ViewResult>(response).Model; Assert.True(setupVm.Confirmation); response = await controller.UpdateWallet(setupVm); Assert.IsType <RedirectToActionResult>(response); response = await controller.WalletSettings(storeId, cryptoCode); var settingsVm = (WalletSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.Equal("CoboVault", settingsVm.Source); // wasabi wallet file content = "{\r\n \"EncryptedSecret\": \"6PYWBQ1zsukowsnTNA57UUx791aBuJusm7E4egXUmF5WGw3tcdG3cmTL57\",\r\n \"ChainCode\": \"waSIVbn8HaoovoQg/0t8IS1+ZCxGsJRGFT21i06nWnc=\",\r\n \"MasterFingerprint\": \"7a7563b5\",\r\n \"ExtPubKey\": \"xpub6CEqRFZ7yZxCFXuEWZBAdnC8bdvu9SRHevaoU2SsW9ZmKhrCShmbpGZWwaR15hdLURf8hg47g4TpPGaqEU8hw5LEJCE35AUhne67XNyFGBk\",\r\n \"PasswordVerified\": false,\r\n \"MinGapLimit\": 21,\r\n \"AccountKeyPath\": \"84'/0'/0'\",\r\n \"BlockchainState\": {\r\n \"Network\": \"RegTest\",\r\n \"Height\": \"0\"\r\n },\r\n \"HdPubKeys\": []\r\n}"; response = await controller.UpdateWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("wasabi.json", content) }); setupVm = (WalletSetupViewModel)Assert.IsType <ViewResult>(response).Model; Assert.True(setupVm.Confirmation); response = await controller.UpdateWallet(setupVm); Assert.IsType <RedirectToActionResult>(response); response = await controller.WalletSettings(storeId, cryptoCode); settingsVm = (WalletSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.Equal("WasabiFile", settingsVm.Source); // Can we upload coldcard settings? (Should fail, we are giving a mainnet file to a testnet network) content = "{\"keystore\": {\"ckcc_xpub\": \"xpub661MyMwAqRbcGVBsTGeNZN6QGVHmMHLdSA4FteGsRrEriu4pnVZMZWnruFFFXkMnyoBjyHndD3Qwcfz4MPzBUxjSevweNFQx7SAYZATtcDw\", \"xpub\": \"ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}"; response = await controller.UpdateWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("coldcard-ypub.json", content) }); setupVm = (WalletSetupViewModel)Assert.IsType <ViewResult>(response).Model; Assert.False(setupVm.Confirmation); // Should fail, we are giving a mainnet file to a testnet network // And with a good file? (upub) content = "{\"keystore\": {\"ckcc_xpub\": \"tpubD6NzVbkrYhZ4YHNiuTdTmHRmbcPRLfqgyneZFCL1mkzkUBjXriQShxTh9HL34FK2mhieasJVk9EzJrUfkFqRNQBjiXgx3n5BhPkxKBoFmaS\", \"xpub\": \"upub5DBYp1qGgsTrkzCptMGZc2x18pquLwGrBw6nS59T4NViZ4cni1mGowQzziy85K8vzkp1jVtWrSkLhqk9KDfvrGeB369wGNYf39kX8rQfiLn\", \"label\": \"Coldcard Import 0x60d1af8b\", \"ckcc_xfp\": 1624354699, \"type\": \"hardware\", \"hw_type\": \"coldcard\", \"derivation\": \"m/49'/0'/0'\"}, \"wallet_type\": \"standard\", \"use_encryption\": false, \"seed_version\": 17}"; response = await controller.UpdateWallet(new WalletSetupViewModel { StoreId = storeId, CryptoCode = cryptoCode, WalletFile = TestUtils.GetFormFile("coldcard-upub.json", content) }); setupVm = (WalletSetupViewModel)Assert.IsType <ViewResult>(response).Model; Assert.True(setupVm.Confirmation); response = await controller.UpdateWallet(setupVm); Assert.IsType <RedirectToActionResult>(response); response = await controller.WalletSettings(storeId, cryptoCode); settingsVm = (WalletSettingsViewModel)Assert.IsType <ViewResult>(response).Model; Assert.Equal("ElectrumFile", settingsVm.Source); // Now let's check that no data has been lost in the process var store = tester.PayTester.StoreRepository.FindStore(storeId).GetAwaiter().GetResult(); var onchainBTC = store.GetSupportedPaymentMethods(tester.PayTester.Networks) #pragma warning disable CS0618 // Type or member is obsolete .OfType <DerivationSchemeSettings>().First(o => o.PaymentId.IsBTCOnChain); #pragma warning restore CS0618 // Type or member is obsolete DerivationSchemeSettings.TryParseFromWalletFile(content, onchainBTC.Network, out var expected); Assert.Equal(expected.ToJson(), onchainBTC.ToJson()); // Let's check that the root hdkey and account key path are taken into account when making a PSBT invoice = await user.BitPay.CreateInvoiceAsync( new Invoice { Price = 1.5m, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); tester.ExplorerNode.Generate(1); var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo.First(c => c.CryptoCode == cryptoCode).Address, tester.ExplorerNode.Network); tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Coins(1m)); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal("paid", invoice.Status); }); var wallet = tester.PayTester.GetController <UIWalletsController>(); var psbt = wallet.CreatePSBT(btcNetwork, onchainBTC, new WalletSendModel() { Outputs = new List <WalletSendModel.TransactionOutput> { new WalletSendModel.TransactionOutput { Amount = 0.5m, DestinationAddress = new Key().PubKey.GetAddress(ScriptPubKeyType.Legacy, btcNetwork.NBitcoinNetwork) .ToString(), } }, FeeSatoshiPerByte = 1 }, default).GetAwaiter().GetResult(); Assert.NotNull(psbt); var root = new Mnemonic( "usage fever hen zero slide mammal silent heavy donate budget pulse say brain thank sausage brand craft about save attract muffin advance illegal cabbage") .DeriveExtKey().AsHDKeyCache(); var account = root.Derive(new KeyPath("m/49'/0'/0'")); Assert.All(psbt.PSBT.Inputs, input => { var keyPath = input.HDKeyPaths.Single(); Assert.False(keyPath.Value.KeyPath.IsHardened); Assert.Equal(account.Derive(keyPath.Value.KeyPath).GetPublicKey(), keyPath.Key); Assert.Equal(keyPath.Value.MasterFingerprint, onchainBTC.AccountKeySettings[0].AccountKey.GetPublicKey().GetHDFingerPrint()); }); } }
public async Task CanHaveLTCOnlyStore() { using (var tester = CreateServerTester()) { tester.ActivateLTC(); await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("LTC"); // First we try payment with a merchant having only BTC var invoice = user.BitPay.CreateInvoice( new Invoice() { Price = 500, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some description", FullNotifications = true }, Facade.Merchant); Assert.Single(invoice.CryptoInfo); Assert.Equal("LTC", invoice.CryptoInfo[0].CryptoCode); Assert.True(invoice.PaymentCodes.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies.ContainsKey("LTC")); Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled); Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC")); Assert.True(invoice.PaymentTotals.ContainsKey("LTC")); var cashCow = tester.LTCExplorerNode; var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network); var firstPayment = Money.Coins(0.1m); cashCow.SendToAddress(invoiceAddress, firstPayment); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal(firstPayment, invoice.CryptoInfo[0].Paid); }); Assert.Single(invoice.CryptoInfo); // Only BTC should be presented var controller = tester.PayTester.GetController <UIInvoiceController>(null); var checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id) .GetAwaiter().GetResult()).Value; Assert.Single(checkout.AvailableCryptos); Assert.Equal("LTC", checkout.CryptoCode); ////////////////////// // Despite it is called BitcoinAddress it should be LTC because BTC is not available Assert.Null(invoice.BitcoinAddress); Assert.NotEqual(1.0m, invoice.Rate); Assert.NotEqual(invoice.BtcDue, invoice.CryptoInfo[0].Due); // Should be BTC rate cashCow.SendToAddress(invoiceAddress, invoice.CryptoInfo[0].Due); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal("paid", invoice.Status); checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id) .GetAwaiter().GetResult()).Value; Assert.Equal("paid", checkout.Status); }); } }
public async Task CanPlayWithPSBT() { using (var tester = ServerTester.Create()) { tester.Start(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); var invoice = user.BitPay.CreateInvoice(new Invoice() { Price = 10, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some \", description", FullNotifications = true }, Facade.Merchant); var cashCow = tester.ExplorerNode; var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network); cashCow.SendToAddress(invoiceAddress, Money.Coins(1.5m)); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal("paid", invoice.Status); }); var walletController = tester.PayTester.GetController <WalletsController>(user.UserId); var walletId = new WalletId(user.StoreId, "BTC"); var sendDestination = new Key().PubKey.Hash.GetAddress(user.SupportedNetwork.NBitcoinNetwork).ToString(); var sendModel = new WalletSendModel() { Destination = sendDestination, Amount = 0.1m, FeeSatoshiPerByte = 1, CurrentBalance = 1.5m }; var vmLedger = await walletController.WalletSend(walletId, sendModel, command : "ledger").AssertViewModelAsync <WalletSendLedgerModel>(); PSBT.Parse(vmLedger.PSBT, user.SupportedNetwork.NBitcoinNetwork); BitcoinAddress.Create(vmLedger.HintChange, user.SupportedNetwork.NBitcoinNetwork); Assert.NotNull(vmLedger.SuccessPath); Assert.NotNull(vmLedger.WebsocketPath); var redirectedPSBT = (string)Assert.IsType <RedirectToActionResult>(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt")).RouteValues["psbt"]; var vmPSBT = walletController.WalletPSBT(walletId, new WalletPSBTViewModel() { PSBT = redirectedPSBT }).AssertViewModel <WalletPSBTViewModel>(); var unsignedPSBT = PSBT.Parse(vmPSBT.PSBT, user.SupportedNetwork.NBitcoinNetwork); Assert.NotNull(vmPSBT.Decoded); var filePSBT = (FileContentResult)(await walletController.WalletPSBT(walletId, vmPSBT, "save-psbt")); PSBT.Load(filePSBT.FileContents, user.SupportedNetwork.NBitcoinNetwork); await walletController.WalletPSBT(walletId, vmPSBT, "ledger").AssertViewModelAsync <WalletSendLedgerModel>(); var vmPSBT2 = await walletController.WalletPSBT(walletId, vmPSBT, "broadcast").AssertViewModelAsync <WalletPSBTViewModel>(); Assert.NotEmpty(vmPSBT2.Errors); Assert.Equal(vmPSBT.Decoded, vmPSBT2.Decoded); Assert.Equal(vmPSBT.PSBT, vmPSBT2.PSBT); var signedPSBT = unsignedPSBT.Clone(); signedPSBT.SignAll(user.ExtKey); vmPSBT.PSBT = signedPSBT.ToBase64(); var psbtReady = await walletController.WalletPSBT(walletId, vmPSBT, "broadcast").AssertViewModelAsync <WalletPSBTReadyViewModel>(); Assert.Equal(2, psbtReady.Destinations.Count); Assert.Contains(psbtReady.Destinations, d => d.Destination == sendDestination && !d.Positive); Assert.Contains(psbtReady.Destinations, d => d.Positive); var redirect = Assert.IsType <RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, psbtReady, command: "broadcast")); Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName); vmPSBT.PSBT = unsignedPSBT.ToBase64(); var combineVM = await walletController.WalletPSBT(walletId, vmPSBT, "combine").AssertViewModelAsync <WalletPSBTCombineViewModel>(); Assert.Equal(vmPSBT.PSBT, combineVM.OtherPSBT); combineVM.PSBT = signedPSBT.ToBase64(); vmPSBT = await walletController.WalletPSBTCombine(walletId, combineVM).AssertViewModelAsync <WalletPSBTViewModel>(); var signedPSBT2 = PSBT.Parse(vmPSBT.PSBT, user.SupportedNetwork.NBitcoinNetwork); Assert.True(signedPSBT.TryFinalize(out _)); Assert.True(signedPSBT2.TryFinalize(out _)); Assert.Equal(signedPSBT, signedPSBT2); // Can use uploaded file? combineVM.PSBT = null; combineVM.UploadedPSBTFile = TestUtils.GetFormFile("signedPSBT", signedPSBT.ToBytes()); vmPSBT = await walletController.WalletPSBTCombine(walletId, combineVM).AssertViewModelAsync <WalletPSBTViewModel>(); signedPSBT2 = PSBT.Parse(vmPSBT.PSBT, user.SupportedNetwork.NBitcoinNetwork); Assert.True(signedPSBT.TryFinalize(out _)); Assert.True(signedPSBT2.TryFinalize(out _)); Assert.Equal(signedPSBT, signedPSBT2); var ready = (await walletController.WalletPSBTReady(walletId, signedPSBT.ToBase64())).AssertViewModel <WalletPSBTReadyViewModel>(); Assert.Equal(signedPSBT.ToBase64(), ready.PSBT); redirect = Assert.IsType <RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt")); Assert.Equal(signedPSBT.ToBase64(), (string)redirect.RouteValues["psbt"]); redirect = Assert.IsType <RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast")); Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName); } }
public void CanComputeCrowdfundModel() { using (var tester = ServerTester.Create()) { tester.Start(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); user.ModifyStore(s => s.NetworkFeeMode = NetworkFeeMode.Never); var apps = user.GetController <AppsController>(); var vm = Assert.IsType <CreateAppViewModel>(Assert.IsType <ViewResult>(apps.CreateApp().Result).Model); vm.Name = "test"; vm.SelectedAppType = AppType.Crowdfund.ToString(); Assert.IsType <RedirectToActionResult>(apps.CreateApp(vm).Result); var appId = Assert.IsType <ListAppsViewModel>(Assert.IsType <ViewResult>(apps.ListApps().Result).Model) .Apps[0].Id; Logs.Tester.LogInformation("We create an invoice with a hardcap"); var crowdfundViewModel = Assert.IsType <UpdateCrowdfundViewModel>(Assert .IsType <ViewResult>(apps.UpdateCrowdfund(appId).Result).Model); crowdfundViewModel.Enabled = true; crowdfundViewModel.EndDate = null; crowdfundViewModel.TargetAmount = 100; crowdfundViewModel.TargetCurrency = "BTC"; crowdfundViewModel.UseAllStoreInvoices = true; crowdfundViewModel.EnforceTargetAmount = true; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result); var anonAppPubsController = tester.PayTester.GetController <AppsPublicController>(); var publicApps = user.GetController <AppsPublicController>(); var model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model); Assert.Equal(crowdfundViewModel.TargetAmount, model.TargetAmount); Assert.Equal(crowdfundViewModel.EndDate, model.EndDate); Assert.Equal(crowdfundViewModel.StartDate, model.StartDate); Assert.Equal(crowdfundViewModel.TargetCurrency, model.TargetCurrency); Assert.Equal(0m, model.Info.CurrentAmount); Assert.Equal(0m, model.Info.CurrentPendingAmount); Assert.Equal(0m, model.Info.ProgressPercentage); Logs.Tester.LogInformation("Unpaid invoices should show as pending contribution because it is hardcap"); Logs.Tester.LogInformation("Because UseAllStoreInvoices is true, we can manually create an invoice and it should show as contribution"); var invoice = user.BitPay.CreateInvoice(new Invoice() { Buyer = new Buyer() { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model); Assert.Equal(0m, model.Info.CurrentAmount); Assert.Equal(1m, model.Info.CurrentPendingAmount); Assert.Equal(0m, model.Info.ProgressPercentage); Assert.Equal(1m, model.Info.PendingProgressPercentage); Logs.Tester.LogInformation("Let's check current amount change once payment is confirmed"); var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network); tester.ExplorerNode.SendToAddress(invoiceAddress, invoice.BtcDue); tester.ExplorerNode.Generate(1); // By default invoice confirmed at 1 block TestUtils.Eventually(() => { model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model); Assert.Equal(1m, model.Info.CurrentAmount); Assert.Equal(0m, model.Info.CurrentPendingAmount); }); Logs.Tester.LogInformation("Because UseAllStoreInvoices is true, let's make sure the invoice is tagged"); var invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult(); Assert.True(invoiceEntity.Version >= InvoiceEntity.InternalTagSupport_Version); Assert.Contains(AppService.GetAppInternalTag(appId), invoiceEntity.InternalTags); crowdfundViewModel.UseAllStoreInvoices = false; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result); Logs.Tester.LogInformation("Because UseAllStoreInvoices is false, let's make sure the invoice is not tagged"); invoice = user.BitPay.CreateInvoice(new Invoice() { Buyer = new Buyer() { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); invoiceEntity = tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id).GetAwaiter().GetResult(); Assert.DoesNotContain(AppService.GetAppInternalTag(appId), invoiceEntity.InternalTags); Logs.Tester.LogInformation("After turning setting a softcap, let's check that only actual payments are counted"); crowdfundViewModel.EnforceTargetAmount = false; crowdfundViewModel.UseAllStoreInvoices = true; Assert.IsType <RedirectToActionResult>(apps.UpdateCrowdfund(appId, crowdfundViewModel).Result); invoice = user.BitPay.CreateInvoice(new Invoice() { Buyer = new Buyer() { email = "*****@*****.**" }, Price = 1m, Currency = "BTC", PosData = "posData", ItemDesc = "Some description", TransactionSpeed = "high", FullNotifications = true }, Facade.Merchant); Assert.Equal(0m, model.Info.CurrentPendingAmount); invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, tester.ExplorerNode.Network); tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Coins(0.5m)); tester.ExplorerNode.SendToAddress(invoiceAddress, Money.Coins(0.2m)); TestUtils.Eventually(() => { model = Assert.IsType <ViewCrowdfundViewModel>(Assert .IsType <ViewResult>(publicApps.ViewCrowdfund(appId, String.Empty).Result).Model); Assert.Equal(0.7m, model.Info.CurrentPendingAmount); }); } }
public async Task CanUseEthereum() { using var s = SeleniumTester.Create("ETHEREUM", true); s.Server.ActivateETH(); await s.StartAsync(); s.RegisterNewUser(true); IWebElement syncSummary = null; TestUtils.Eventually(() => { syncSummary = s.Driver.FindElement(By.Id("modalDialog")); Assert.True(syncSummary.Displayed); }); var web3Link = syncSummary.FindElement(By.LinkText("Configure Web3")); web3Link.Click(); s.Driver.FindElement(By.Id("Web3ProviderUrl")).SendKeys("https://ropsten-rpc.linkpool.io"); s.Driver.FindElement(By.Id("saveButton")).Click(); s.AssertHappyMessage(); TestUtils.Eventually(() => { s.Driver.Navigate().Refresh(); s.Driver.AssertElementNotFound(By.Id("modalDialog")); }); var store = s.CreateNewStore(); s.Driver.FindElement(By.LinkText("Ethereum")).Click(); var seed = new Mnemonic(Wordlist.English); s.Driver.FindElement(By.Id("ModifyETH")).Click(); s.Driver.FindElement(By.Id("Seed")).SendKeys(seed.ToString()); s.SetCheckbox(s.Driver.FindElement(By.Id("StoreSeed")), true); s.SetCheckbox(s.Driver.FindElement(By.Id("Enabled")), true); s.Driver.FindElement(By.Id("SaveButton")).Click(); s.AssertHappyMessage(); s.Driver.FindElement(By.Id("ModifyUSDT20")).Click(); s.Driver.FindElement(By.Id("Seed")).SendKeys(seed.ToString()); s.SetCheckbox(s.Driver.FindElement(By.Id("StoreSeed")), true); s.SetCheckbox(s.Driver.FindElement(By.Id("Enabled")), true); s.Driver.FindElement(By.Id("SaveButton")).Click(); s.AssertHappyMessage(); var invoiceId = s.CreateInvoice(store.storeName, 10); s.GoToInvoiceCheckout(invoiceId); var currencyDropdownButton = s.Driver.WaitForElement(By.ClassName("payment__currencies")); Assert.Contains("ETH", currencyDropdownButton.Text); s.Driver.FindElement(By.Id("copy-tab")).Click(); var ethAddress = s.Driver.FindElements(By.ClassName("copySectionBox")) .Single(element => element.FindElement(By.TagName("label")).Text .Contains("Address", StringComparison.InvariantCultureIgnoreCase)).FindElement(By.TagName("input")) .GetAttribute("value"); currencyDropdownButton.Click(); var elements = s.Driver.FindElement(By.ClassName("vex-content")).FindElements(By.ClassName("vexmenuitem")); Assert.Equal(2, elements.Count); elements.Single(element => element.Text.Contains("USDT20")).Click(); s.Driver.FindElement(By.Id("copy-tab")).Click(); var usdtAddress = s.Driver.FindElements(By.ClassName("copySectionBox")) .Single(element => element.FindElement(By.TagName("label")).Text .Contains("Address", StringComparison.InvariantCultureIgnoreCase)).FindElement(By.TagName("input")) .GetAttribute("value"); Assert.Equal(usdtAddress, ethAddress); }
public async Task CanPlayWithPSBT() { using (var tester = ServerTester.Create()) { await tester.StartAsync(); var user = tester.NewAccount(); user.GrantAccess(); user.RegisterDerivationScheme("BTC"); var invoice = user.BitPay.CreateInvoice(new Invoice() { Price = 10, Currency = "USD", PosData = "posData", OrderId = "orderId", ItemDesc = "Some \", description", FullNotifications = true }, Facade.Merchant); var cashCow = tester.ExplorerNode; var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network); cashCow.SendToAddress(invoiceAddress, Money.Coins(1.5m)); TestUtils.Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); Assert.Equal("paid", invoice.Status); }); var walletController = user.GetController <WalletsController>(); var walletId = new WalletId(user.StoreId, "BTC"); var sendDestination = new Key().PubKey.Hash.GetAddress(user.SupportedNetwork.NBitcoinNetwork).ToString(); var sendModel = new WalletSendModel() { Outputs = new List <WalletSendModel.TransactionOutput>() { new WalletSendModel.TransactionOutput() { DestinationAddress = sendDestination, Amount = 0.1m, } }, FeeSatoshiPerByte = 1, CurrentBalance = 1.5m }; string redirectedPSBT = AssertRedirectedPSBT(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt"), nameof(walletController.WalletPSBT)); var vmPSBT = await walletController.WalletPSBT(walletId, new WalletPSBTViewModel() { PSBT = redirectedPSBT }).AssertViewModelAsync <WalletPSBTViewModel>(); var unsignedPSBT = PSBT.Parse(vmPSBT.PSBT, user.SupportedNetwork.NBitcoinNetwork); Assert.NotNull(vmPSBT.Decoded); var filePSBT = (FileContentResult)(await walletController.WalletPSBT(walletId, vmPSBT, "save-psbt")); PSBT.Load(filePSBT.FileContents, user.SupportedNetwork.NBitcoinNetwork); var vmPSBT2 = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() { SigningContext = new SigningContextModel() { PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady)) } }).AssertViewModelAsync <WalletPSBTReadyViewModel>(); Assert.NotEmpty(vmPSBT2.Inputs.Where(i => i.Error != null)); Assert.Equal(vmPSBT.PSBT, vmPSBT2.SigningContext.PSBT); var signedPSBT = unsignedPSBT.Clone(); signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath); vmPSBT.PSBT = signedPSBT.ToBase64(); var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel { SigningContext = new SigningContextModel { PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady)) } }).AssertViewModelAsync <WalletPSBTReadyViewModel>(); Assert.Equal(2 + 1, psbtReady.Destinations.Count); // The fee is a destination Assert.Contains(psbtReady.Destinations, d => d.Destination == sendDestination && !d.Positive); Assert.Contains(psbtReady.Destinations, d => d.Positive); vmPSBT.PSBT = unsignedPSBT.ToBase64(); var combineVM = await walletController.WalletPSBT(walletId, vmPSBT, "combine").AssertViewModelAsync <WalletPSBTCombineViewModel>(); Assert.Equal(vmPSBT.PSBT, combineVM.OtherPSBT); combineVM.PSBT = signedPSBT.ToBase64(); var psbt = AssertRedirectedPSBT(await walletController.WalletPSBTCombine(walletId, combineVM), nameof(walletController.WalletPSBT)); var signedPSBT2 = PSBT.Parse(psbt, user.SupportedNetwork.NBitcoinNetwork); Assert.True(signedPSBT.TryFinalize(out _)); Assert.True(signedPSBT2.TryFinalize(out _)); Assert.Equal(signedPSBT, signedPSBT2); // Can use uploaded file? combineVM.PSBT = null; combineVM.UploadedPSBTFile = TestUtils.GetFormFile("signedPSBT", signedPSBT.ToBytes()); psbt = AssertRedirectedPSBT(await walletController.WalletPSBTCombine(walletId, combineVM), nameof(walletController.WalletPSBT)); signedPSBT2 = PSBT.Parse(psbt, user.SupportedNetwork.NBitcoinNetwork); Assert.True(signedPSBT.TryFinalize(out _)); Assert.True(signedPSBT2.TryFinalize(out _)); Assert.Equal(signedPSBT, signedPSBT2); var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel { SigningContext = new SigningContextModel(signedPSBT) })).AssertViewModel <WalletPSBTReadyViewModel>(); Assert.Equal(signedPSBT.ToBase64(), ready.SigningContext.PSBT); psbt = AssertRedirectedPSBT(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt"), nameof(walletController.WalletPSBT)); Assert.Equal(signedPSBT.ToBase64(), psbt); var redirect = Assert.IsType <RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast")); Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName); //test base64 psbt file Assert.False(string.IsNullOrEmpty(Assert.IsType <WalletPSBTViewModel>( Assert.IsType <ViewResult>( await walletController.WalletPSBT(walletId, new WalletPSBTViewModel() { UploadedPSBTFile = TestUtils.GetFormFile("base64", signedPSBT.ToBase64()) })).Model).PSBT)); } }