diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index 278d38970..066095766 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -77,10 +77,10 @@ namespace BTCPayServer.Tests return usr; } - public void AddDerivationScheme() + public void AddDerivationScheme(string derivationScheme = "xpub661MyMwAqRbcGABgHMUXDzPzH1tU7eZaAaJQXhDXsSxsqyQzQeU6kznNfSuAyqAK9UaWSaZaMFdNiY5BCF4zBPAzSnwfUAwUhwttuAKwfRX-[legacy]") { Driver.FindElement(By.Id("ModifyBTC")).ForceClick(); - Driver.FindElement(By.Id("DerivationScheme")).SendKeys("xpub661MyMwAqRbcGABgHMUXDzPzH1tU7eZaAaJQXhDXsSxsqyQzQeU6kznNfSuAyqAK9UaWSaZaMFdNiY5BCF4zBPAzSnwfUAwUhwttuAKwfRX-[legacy]"); + Driver.FindElement(By.Id("DerivationScheme")).SendKeys(derivationScheme); Driver.FindElement(By.Id("Continue")).ForceClick(); Driver.FindElement(By.Id("Confirm")).ForceClick(); Driver.FindElement(By.Id("Save")).ForceClick(); @@ -90,6 +90,7 @@ namespace BTCPayServer.Tests public void ClickOnAllSideMenus() { var links = Driver.FindElements(By.CssSelector(".nav-pills .nav-link")).Select(c => c.GetAttribute("href")).ToList(); + Driver.AssertNoError(); Assert.NotEmpty(links); foreach (var l in links) { diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index e5a135dcb..189124561 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -257,14 +257,46 @@ namespace BTCPayServer.Tests s.Start(); s.RegisterNewUser(); s.CreateNewStore(); - s.AddDerivationScheme(); + + // In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0', then try to use the seed + // to sign the transaction + var 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"; + var root = new Mnemonic(mnemonic).DeriveExtKey(); + s.AddDerivationScheme("ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD"); + var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create("bcrt1qmxg8fgnmkp354vhe78j6sr4ut64tyz2xyejel4", Network.RegTest), Money.Coins(1.0m)); + s.Driver.FindElement(By.Id("Wallets")).Click(); s.Driver.FindElement(By.LinkText("Manage")).Click(); s.ClickOnAllSideMenus(); - s.Driver.Quit(); + // We setup the fingerprint and the account key path + s.Driver.FindElement(By.Id("WalletSettings")).ForceClick(); + s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).SendKeys("8bafd160"); + s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).SendKeys("m/49'/0'/0'" + Keys.Enter); + + // Check the tx sent earlier arrived + s.Driver.FindElement(By.Id("WalletTransactions")).ForceClick(); + var walletTransactionLink = s.Driver.Url; + Assert.Contains(tx.ToString(), s.Driver.PageSource); + + // Send to bob + s.Driver.FindElement(By.Id("WalletSend")).Click(); + var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); + s.Driver.FindElement(By.Id("Destination")).SendKeys(bob.ToString()); + s.Driver.FindElement(By.Id("Amount")).SendKeys("1"); + s.Driver.FindElement(By.Id("SendMenu")).Click(); + s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click(); + + // Input the seed + s.Driver.FindElement(By.Id("SeedOrKey")).SendKeys(mnemonic + Keys.Enter); + + // Broadcast + Assert.Contains(bob.ToString(), s.Driver.PageSource); + Assert.Contains("1.00000000", s.Driver.PageSource); + s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); + Assert.Equal(walletTransactionLink, s.Driver.Url); } } } diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 5236c89b0..a2016ae45 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -2707,6 +2707,7 @@ donation: 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(); Assert.True(DerivationSchemeSettings.TryParseFromColdcard("{\"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}", mainnet, out var settings)); Assert.Equal(root.GetPublicKey().GetHDFingerPrint(), settings.AccountKeySettings[0].RootFingerprint); + Assert.Equal(settings.AccountKeySettings[0].RootFingerprint, HDFingerprint.TryParse("8bafd160", out var hd) ? hd : default); Assert.Equal("Coldcard Import 0x60d1af8b", settings.Label); Assert.Equal("49'/0'/0'", settings.AccountKeySettings[0].AccountKeyPath.ToString()); Assert.Equal("ypub6WWc2gWwHbdnAAyJDnR4SPL1phRh7REqrPBfZeizaQ1EmTshieRXJC3Z5YoU4wkcdKHEjQGkh6AYEzCQC1Kz3DNaWSwdc1pc8416hAjzqyD", settings.AccountOriginal); diff --git a/BTCPayServer/Views/Wallets/_Nav.cshtml b/BTCPayServer/Views/Wallets/_Nav.cshtml index 71569fc9e..a5318ff0b 100644 --- a/BTCPayServer/Views/Wallets/_Nav.cshtml +++ b/BTCPayServer/Views/Wallets/_Nav.cshtml @@ -1,10 +1,10 @@ @inject SignInManager SignInManager