Refactor common data structure for wallet into SigningContext

This commit is contained in:
nicolas.dorier
2020-05-25 06:27:01 +09:00
parent 25e6f82aa3
commit 35432d919c
15 changed files with 129 additions and 126 deletions

View File

@@ -67,8 +67,8 @@ namespace BTCPayServer.Tests
CurrentBalance = 1.5m CurrentBalance = 1.5m
}; };
var vmLedger = await walletController.WalletSend(walletId, sendModel, command: "ledger").AssertViewModelAsync<WalletSendLedgerModel>(); var vmLedger = await walletController.WalletSend(walletId, sendModel, command: "ledger").AssertViewModelAsync<WalletSendLedgerModel>();
PSBT.Parse(vmLedger.PSBT, user.SupportedNetwork.NBitcoinNetwork); PSBT.Parse(vmLedger.SigningContext.PSBT, user.SupportedNetwork.NBitcoinNetwork);
BitcoinAddress.Create(vmLedger.HintChange, user.SupportedNetwork.NBitcoinNetwork); BitcoinAddress.Create(vmLedger.SigningContext.ChangeAddress, user.SupportedNetwork.NBitcoinNetwork);
Assert.NotNull(vmLedger.WebsocketPath); Assert.NotNull(vmLedger.WebsocketPath);
string redirectedPSBT = AssertRedirectedPSBT(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt"), nameof(walletController.WalletPSBT)); string redirectedPSBT = AssertRedirectedPSBT(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt"), nameof(walletController.WalletPSBT));
@@ -82,17 +82,23 @@ namespace BTCPayServer.Tests
await walletController.WalletPSBT(walletId, vmPSBT, "ledger").AssertViewModelAsync<WalletSendLedgerModel>(); await walletController.WalletPSBT(walletId, vmPSBT, "ledger").AssertViewModelAsync<WalletSendLedgerModel>();
var vmPSBT2 = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() var vmPSBT2 = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{ {
PSBT = AssertRedirectedPSBT( await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady)) SigningContext = new SigningContextModel()
{
PSBT = AssertRedirectedPSBT( await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady))
}
} ).AssertViewModelAsync<WalletPSBTReadyViewModel>(); } ).AssertViewModelAsync<WalletPSBTReadyViewModel>();
Assert.NotEmpty(vmPSBT2.Inputs.Where(i => i.Error != null)); Assert.NotEmpty(vmPSBT2.Inputs.Where(i => i.Error != null));
Assert.Equal(vmPSBT.PSBT, vmPSBT2.PSBT); Assert.Equal(vmPSBT.PSBT, vmPSBT2.SigningContext.PSBT);
var signedPSBT = unsignedPSBT.Clone(); var signedPSBT = unsignedPSBT.Clone();
signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath); signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath);
vmPSBT.PSBT = signedPSBT.ToBase64(); vmPSBT.PSBT = signedPSBT.ToBase64();
var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{ {
PSBT = AssertRedirectedPSBT( await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady)) SigningContext = new SigningContextModel()
{
PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady))
}
} ).AssertViewModelAsync<WalletPSBTReadyViewModel>(); } ).AssertViewModelAsync<WalletPSBTReadyViewModel>();
Assert.Equal(2 + 1, psbtReady.Destinations.Count); // The fee is a destination 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.Destination == sendDestination && !d.Positive);
@@ -122,9 +128,12 @@ namespace BTCPayServer.Tests
var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{ {
PSBT = signedPSBT.ToBase64() SigningContext = new SigningContextModel()
{
PSBT = signedPSBT.ToBase64()
}
})).AssertViewModel<WalletPSBTReadyViewModel>(); })).AssertViewModel<WalletPSBTReadyViewModel>();
Assert.Equal(signedPSBT.ToBase64(), ready.PSBT); Assert.Equal(signedPSBT.ToBase64(), ready.SigningContext.PSBT);
psbt = AssertRedirectedPSBT(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt"), nameof(walletController.WalletPSBT)); psbt = AssertRedirectedPSBT(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt"), nameof(walletController.WalletPSBT));
Assert.Equal(signedPSBT.ToBase64(), psbt); Assert.Equal(signedPSBT.ToBase64(), psbt);
redirect = Assert.IsType<RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast")); redirect = Assert.IsType<RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast"));

View File

@@ -2,8 +2,8 @@
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" /> <Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
<Import Project="../Build/Common.csproj" /> <Import Project="../Build/Common.csproj" />
<PropertyGroup Condition="'$(Configuration)' == 'Debug' And '$(RazorCompileOnBuild)' != 'true'"> <PropertyGroup Condition="'$(Configuration)' == 'Debug' And '$(RazorCompileOnBuild)' != 'true'">
<!--<RazorCompileOnBuild>false</RazorCompileOnBuild> <RazorCompileOnBuild>false</RazorCompileOnBuild>
<DefineConstants>$(DefineConstants);RAZOR_RUNTIME_COMPILE</DefineConstants>--> <DefineConstants>$(DefineConstants);RAZOR_RUNTIME_COMPILE</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@@ -187,6 +187,9 @@
<Content Update="Views\Wallets\ListWallets.cshtml"> <Content Update="Views\Wallets\ListWallets.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack> <Pack>$(IncludeRazorContentInPack)</Pack>
</Content> </Content>
<Content Update="Views\Wallets\WalletPSBT - Copy.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>
<Content Update="Views\Wallets\WalletPSBTCombine.cshtml"> <Content Update="Views\Wallets\WalletPSBTCombine.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack> <Pack>$(IncludeRazorContentInPack)</Pack>
</Content> </Content>

View File

@@ -101,7 +101,7 @@ namespace BTCPayServer.Controllers
return View(vm); return View(vm);
} }
var res = await TryHandleSigningCommands(walletId, psbt, command, vm.SigningContext, null); var res = await TryHandleSigningCommands(walletId, psbt, command, vm.SigningContext);
if (res != null) if (res != null)
{ {
return res; return res;
@@ -137,7 +137,10 @@ namespace BTCPayServer.Controllers
{ {
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
{ {
PSBT = psbt.ToBase64() SigningContext = new SigningContextModel()
{
PSBT = psbt.ToBase64()
}
}); });
} }
case "combine": case "combine":
@@ -183,7 +186,7 @@ namespace BTCPayServer.Controllers
private async Task FetchTransactionDetails(DerivationSchemeSettings derivationSchemeSettings, WalletPSBTReadyViewModel vm, BTCPayNetwork network) private async Task FetchTransactionDetails(DerivationSchemeSettings derivationSchemeSettings, WalletPSBTReadyViewModel vm, BTCPayNetwork network)
{ {
var psbtObject = PSBT.Parse(vm.PSBT, network.NBitcoinNetwork); var psbtObject = PSBT.Parse(vm.SigningContext.PSBT, network.NBitcoinNetwork);
if (!psbtObject.IsAllFinalized()) if (!psbtObject.IsAllFinalized())
psbtObject = await ExplorerClientProvider.UpdatePSBT(derivationSchemeSettings, psbtObject) ?? psbtObject; psbtObject = await ExplorerClientProvider.UpdatePSBT(derivationSchemeSettings, psbtObject) ?? psbtObject;
IHDKey signingKey = null; IHDKey signingKey = null;
@@ -296,7 +299,7 @@ namespace BTCPayServer.Controllers
DerivationSchemeSettings derivationSchemeSettings = null; DerivationSchemeSettings derivationSchemeSettings = null;
try try
{ {
psbt = PSBT.Parse(vm.PSBT, network.NBitcoinNetwork); psbt = PSBT.Parse(vm.SigningContext.PSBT, network.NBitcoinNetwork);
derivationSchemeSettings = GetDerivationSchemeSettings(walletId); derivationSchemeSettings = GetDerivationSchemeSettings(walletId);
if (derivationSchemeSettings == null) if (derivationSchemeSettings == null)
return NotFound(); return NotFound();
@@ -322,8 +325,8 @@ namespace BTCPayServer.Controllers
proposedPayjoin = proposedPayjoin.SignAll(derivationSchemeSettings.AccountDerivation, proposedPayjoin = proposedPayjoin.SignAll(derivationSchemeSettings.AccountDerivation,
extKey, extKey,
RootedKeyPath.Parse(vm.SigningKeyPath)); RootedKeyPath.Parse(vm.SigningKeyPath));
vm.PSBT = proposedPayjoin.ToBase64(); vm.SigningContext.PSBT = proposedPayjoin.ToBase64();
vm.OriginalPSBT = psbt.ToBase64(); vm.SigningContext.OriginalPSBT = psbt.ToBase64();
proposedPayjoin.Finalize(); proposedPayjoin.Finalize();
var hash = proposedPayjoin.ExtractTransaction().GetHash(); var hash = proposedPayjoin.ExtractTransaction().GetHash();
_EventAggregator.Publish(new UpdateTransactionLabel() _EventAggregator.Publish(new UpdateTransactionLabel()
@@ -359,7 +362,9 @@ namespace BTCPayServer.Controllers
$"The amount being sent may appear higher but is in fact almost same.<br/><br/>" + $"The amount being sent may appear higher but is in fact almost same.<br/><br/>" +
$"If you cancel or refuse to sign this transaction, the payment will proceed without payjoin" $"If you cancel or refuse to sign this transaction, the payment will proceed without payjoin"
}); });
return ViewVault(walletId, proposedPayjoin, vm.SigningContext, psbt); vm.SigningContext.PSBT = proposedPayjoin.ToBase64();
vm.SigningContext.OriginalPSBT = psbt.ToBase64();
return ViewVault(walletId, vm.SigningContext);
} }
} }
catch (PayjoinReceiverException ex) catch (PayjoinReceiverException ex)
@@ -397,7 +402,7 @@ namespace BTCPayServer.Controllers
var broadcastResult = await ExplorerClientProvider.GetExplorerClient(network).BroadcastAsync(transaction); var broadcastResult = await ExplorerClientProvider.GetExplorerClient(network).BroadcastAsync(transaction);
if (!broadcastResult.Success) if (!broadcastResult.Success)
{ {
if (!string.IsNullOrEmpty(vm.OriginalPSBT)) if (!string.IsNullOrEmpty(vm.SigningContext.OriginalPSBT))
{ {
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
@@ -405,8 +410,8 @@ namespace BTCPayServer.Controllers
AllowDismiss = false, AllowDismiss = false,
Html = $"The payjoin transaction could not be broadcasted.<br/>({broadcastResult.RPCCode} {broadcastResult.RPCCodeMessage} {broadcastResult.RPCMessage}).<br/>The transaction has been reverted back to its original format and has been broadcast." Html = $"The payjoin transaction could not be broadcasted.<br/>({broadcastResult.RPCCode} {broadcastResult.RPCCodeMessage} {broadcastResult.RPCMessage}).<br/>The transaction has been reverted back to its original format and has been broadcast."
}); });
vm.PSBT = vm.OriginalPSBT; vm.SigningContext.PSBT = vm.SigningContext.OriginalPSBT;
vm.OriginalPSBT = null; vm.SigningContext.OriginalPSBT = null;
return await WalletPSBTReady(walletId, vm, "broadcast"); return await WalletPSBTReady(walletId, vm, "broadcast");
} }
@@ -470,16 +475,17 @@ namespace BTCPayServer.Controllers
} }
private async Task<IActionResult> TryHandleSigningCommands(WalletId walletId, PSBT psbt, string command, private async Task<IActionResult> TryHandleSigningCommands(WalletId walletId, PSBT psbt, string command,
SigningContextModel signingContext, BitcoinAddress changeAddress) SigningContextModel signingContext)
{ {
signingContext.PSBT = psbt.ToBase64();
switch (command ) switch (command )
{ {
case "vault": case "vault":
return ViewVault(walletId, psbt, signingContext); return ViewVault(walletId, signingContext);
case "ledger": case "ledger":
return ViewWalletSendLedger(walletId, psbt, changeAddress); return ViewWalletSendLedger(walletId, signingContext);
case "seed": case "seed":
return SignWithSeed(walletId, psbt.ToBase64(), signingContext); return SignWithSeed(walletId, signingContext);
case "nbx-seed": case "nbx-seed":
if (await CanUseHotWallet()) if (await CanUseHotWallet())
{ {
@@ -487,9 +493,8 @@ namespace BTCPayServer.Controllers
var extKey = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode) var extKey = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.GetMetadataAsync<string>(derivationScheme.AccountDerivation, .GetMetadataAsync<string>(derivationScheme.AccountDerivation,
WellknownMetadataKeys.MasterHDKey); WellknownMetadataKeys.MasterHDKey);
return SignWithSeed(walletId, return SignWithSeed(walletId,
new SignWithSeedViewModel() {SeedOrKey = extKey, PSBT = psbt.ToBase64(), SigningContext = signingContext }); new SignWithSeedViewModel() {SeedOrKey = extKey, SigningContext = signingContext });
} }
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {

View File

@@ -97,7 +97,7 @@ namespace BTCPayServer.Controllers
} }
// Borrowed from https://github.com/ManageIQ/guides/blob/master/labels.md // Borrowed from https://github.com/ManageIQ/guides/blob/master/labels.md
string[] LabelColorScheme = new string[] string[] LabelColorScheme = new string[]
{ {
"#fbca04", "#fbca04",
"#0e8a16", "#0e8a16",
@@ -117,10 +117,10 @@ namespace BTCPayServer.Controllers
// addlabelclick is if the user click on existing label. For some reason, reusing the same name attribute for both // addlabelclick is if the user click on existing label. For some reason, reusing the same name attribute for both
// does not work // does not work
[ModelBinder(typeof(WalletIdModelBinder))] [ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, string transactionId, WalletId walletId, string transactionId,
string addlabel = null, string addlabel = null,
string addlabelclick = null, string addlabelclick = null,
string addcomment = null, string addcomment = null,
string removelabel = null) string removelabel = null)
{ {
addlabel = addlabel ?? addlabelclick; addlabel = addlabel ?? addlabelclick;
@@ -135,7 +135,7 @@ namespace BTCPayServer.Controllers
} }
catch { } catch { }
///////// /////////
DerivationSchemeSettings paymentMethod = GetDerivationSchemeSettings(walletId); DerivationSchemeSettings paymentMethod = GetDerivationSchemeSettings(walletId);
if (paymentMethod == null) if (paymentMethod == null)
return NotFound(); return NotFound();
@@ -147,7 +147,7 @@ namespace BTCPayServer.Controllers
var walletTransactionsInfo = await walletTransactionsInfoAsync; var walletTransactionsInfo = await walletTransactionsInfoAsync;
if (addlabel != null) if (addlabel != null)
{ {
addlabel = addlabel.Trim().TrimStart('{').ToLowerInvariant().Replace(',',' ').Truncate(MaxLabelSize); addlabel = addlabel.Trim().TrimStart('{').ToLowerInvariant().Replace(',', ' ').Truncate(MaxLabelSize);
var labels = _labelFactory.GetLabels(walletBlobInfo, Request); var labels = _labelFactory.GetLabels(walletBlobInfo, Request);
if (!walletTransactionsInfo.TryGetValue(transactionId, out var walletTransactionInfo)) if (!walletTransactionsInfo.TryGetValue(transactionId, out var walletTransactionInfo))
{ {
@@ -290,7 +290,7 @@ namespace BTCPayServer.Controllers
if (walletTransactionsInfo.TryGetValue(tx.TransactionId.ToString(), out var transactionInfo)) if (walletTransactionsInfo.TryGetValue(tx.TransactionId.ToString(), out var transactionInfo))
{ {
var labels = _labelFactory.GetLabels(walletBlob, transactionInfo, Request); var labels = _labelFactory.GetLabels(walletBlob, transactionInfo, Request);
vm.Labels.AddRange(labels); vm.Labels.AddRange(labels);
model.Labels.AddRange(labels); model.Labels.AddRange(labels);
vm.Comment = transactionInfo.Comment; vm.Comment = transactionInfo.Comment;
@@ -359,7 +359,7 @@ namespace BTCPayServer.Controllers
} }
var address = cachedAddress.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork); var address = cachedAddress.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork);
ExplorerClientProvider.GetExplorerClient(network) ExplorerClientProvider.GetExplorerClient(network)
.CancelReservation(cachedAddress.DerivationStrategy, new[] {cachedAddress.KeyPath}); .CancelReservation(cachedAddress.DerivationStrategy, new[] { cachedAddress.KeyPath });
this.TempData.SetStatusMessageModel(new StatusMessageModel() this.TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
AllowDismiss = true, AllowDismiss = true,
@@ -373,7 +373,7 @@ namespace BTCPayServer.Controllers
_WalletReceiveStateService.Set(walletId, reserve); _WalletReceiveStateService.Set(walletId, reserve);
break; break;
} }
return RedirectToAction(nameof(WalletReceive), new {walletId}); return RedirectToAction(nameof(WalletReceive), new { walletId });
} }
private async Task<bool> CanUseHotWallet() private async Task<bool> CanUseHotWallet()
@@ -384,7 +384,7 @@ namespace BTCPayServer.Controllers
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>(); var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>();
return policies?.AllowHotWalletForAll is true; return policies?.AllowHotWalletForAll is true;
} }
[HttpGet] [HttpGet]
[Route("{walletId}/send")] [Route("{walletId}/send")]
public async Task<IActionResult> WalletSend( public async Task<IActionResult> WalletSend(
@@ -405,7 +405,7 @@ namespace BTCPayServer.Controllers
rateRules.Spread = 0.0m; rateRules.Spread = 0.0m;
var currencyPair = new Rating.CurrencyPair(paymentMethod.PaymentId.CryptoCode, GetCurrencyCode(storeData.DefaultLang) ?? "USD"); var currencyPair = new Rating.CurrencyPair(paymentMethod.PaymentId.CryptoCode, GetCurrencyCode(storeData.DefaultLang) ?? "USD");
double.TryParse(defaultAmount, out var amount); double.TryParse(defaultAmount, out var amount);
var model = new WalletSendModel() var model = new WalletSendModel()
{ {
Outputs = new List<WalletSendModel.TransactionOutput>() Outputs = new List<WalletSendModel.TransactionOutput>()
{ {
@@ -417,11 +417,11 @@ namespace BTCPayServer.Controllers
}, },
CryptoCode = walletId.CryptoCode CryptoCode = walletId.CryptoCode
}; };
if (!string.IsNullOrEmpty(bip21)) if (!string.IsNullOrEmpty(bip21))
{ {
LoadFromBIP21(model, bip21, network); LoadFromBIP21(model, bip21, network);
} }
var feeProvider = _feeRateProvider.CreateFeeProvider(network); var feeProvider = _feeRateProvider.CreateFeeProvider(network);
var recommendedFees = var recommendedFees =
new[] new[]
{ {
@@ -433,7 +433,7 @@ namespace BTCPayServer.Controllers
{ {
var result = await feeProvider.GetFeeRateAsync( var result = await feeProvider.GetFeeRateAsync(
(int)network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time)); (int)network.NBitcoinNetwork.Consensus.GetExpectedBlocksFor(time));
return new WalletSendModel.FeeRateOption() {Target = time, FeeRate = result.SatoshiPerByte}; return new WalletSendModel.FeeRateOption() { Target = time, FeeRate = result.SatoshiPerByte };
} }
catch (Exception) catch (Exception)
{ {
@@ -446,7 +446,7 @@ namespace BTCPayServer.Controllers
.GetMetadataAsync<string>(GetDerivationSchemeSettings(walletId).AccountDerivation, .GetMetadataAsync<string>(GetDerivationSchemeSettings(walletId).AccountDerivation,
WellknownMetadataKeys.MasterHDKey)); WellknownMetadataKeys.MasterHDKey));
model.CurrentBalance = await balance; model.CurrentBalance = await balance;
await Task.WhenAll(recommendedFees); await Task.WhenAll(recommendedFees);
model.RecommendedSatoshiPerByte = model.RecommendedSatoshiPerByte =
recommendedFees.Select(tuple => tuple.Result).Where(option => option != null).ToList(); recommendedFees.Select(tuple => tuple.Result).Where(option => option != null).ToList();
@@ -474,7 +474,7 @@ namespace BTCPayServer.Controllers
} }
return View(model); return View(model);
} }
[HttpPost] [HttpPost]
[Route("{walletId}/send")] [Route("{walletId}/send")]
@@ -498,11 +498,11 @@ namespace BTCPayServer.Controllers
{ {
LoadFromBIP21(vm, bip21, network); LoadFromBIP21(vm, bip21, network);
} }
decimal transactionAmountSum = 0; decimal transactionAmountSum = 0;
if (command == "toggle-input-selection") if (command == "toggle-input-selection")
{ {
vm.InputSelection = !vm.InputSelection; vm.InputSelection = !vm.InputSelection;
} }
if (vm.InputSelection) if (vm.InputSelection)
{ {
@@ -510,7 +510,7 @@ namespace BTCPayServer.Controllers
var walletBlobAsync = await WalletRepository.GetWalletInfo(walletId); var walletBlobAsync = await WalletRepository.GetWalletInfo(walletId);
var walletTransactionsInfoAsync = await WalletRepository.GetWalletTransactionsInfo(walletId); var walletTransactionsInfoAsync = await WalletRepository.GetWalletTransactionsInfo(walletId);
var utxos = await _walletProvider.GetWallet(network).GetUnspentCoins(schemeSettings.AccountDerivation, cancellation); var utxos = await _walletProvider.GetWallet(network).GetUnspentCoins(schemeSettings.AccountDerivation, cancellation);
vm.InputsAvailable = utxos.Select(coin => vm.InputsAvailable = utxos.Select(coin =>
{ {
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info); walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info);
@@ -519,7 +519,7 @@ namespace BTCPayServer.Controllers
Outpoint = coin.OutPoint.ToString(), Outpoint = coin.OutPoint.ToString(),
Amount = coin.Value.GetValue(network), Amount = coin.Value.GetValue(network),
Comment = info?.Comment, Comment = info?.Comment,
Labels = info == null? null : _labelFactory.GetLabels(walletBlobAsync, info, Request), Labels = info == null ? null : _labelFactory.GetLabels(walletBlobAsync, info, Request),
Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, coin.OutPoint.Hash.ToString()) Link = string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, coin.OutPoint.Hash.ToString())
}; };
}).ToArray(); }).ToArray();
@@ -544,7 +544,7 @@ namespace BTCPayServer.Controllers
if (command.StartsWith("remove-output", StringComparison.InvariantCultureIgnoreCase)) if (command.StartsWith("remove-output", StringComparison.InvariantCultureIgnoreCase))
{ {
ModelState.Clear(); ModelState.Clear();
var index = int.Parse(command.Substring(command.IndexOf(":",StringComparison.InvariantCultureIgnoreCase) + 1), CultureInfo.InvariantCulture); var index = int.Parse(command.Substring(command.IndexOf(":", StringComparison.InvariantCultureIgnoreCase) + 1), CultureInfo.InvariantCulture);
vm.Outputs.RemoveAt(index); vm.Outputs.RemoveAt(index);
return View(vm); return View(vm);
} }
@@ -569,12 +569,12 @@ namespace BTCPayServer.Controllers
try try
{ {
BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork); BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork);
} }
catch catch
{ {
var inputName = var inputName =
string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) + string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) +
nameof(transactionOutput.DestinationAddress); nameof(transactionOutput.DestinationAddress);
ModelState.AddModelError(inputName, "Invalid address"); ModelState.AddModelError(inputName, "Invalid address");
@@ -599,7 +599,8 @@ namespace BTCPayServer.Controllers
vm.AddModelError(model => model.Outputs[subtractFeesOutput].SubtractFeesFromOutput, vm.AddModelError(model => model.Outputs[subtractFeesOutput].SubtractFeesFromOutput,
"You can only subtract fees from one output", this); "You can only subtract fees from one output", this);
} }
}else if (vm.CurrentBalance == transactionAmountSum && !substractFees) }
else if (vm.CurrentBalance == transactionAmountSum && !substractFees)
{ {
ModelState.AddModelError(string.Empty, ModelState.AddModelError(string.Empty,
"You are sending your entire balance, you should subtract the fees from an output"); "You are sending your entire balance, you should subtract the fees from an output");
@@ -633,7 +634,7 @@ namespace BTCPayServer.Controllers
} }
} }
if (!ModelState.IsValid) if (!ModelState.IsValid)
return View(vm); return View(vm);
DerivationSchemeSettings derivationScheme = GetDerivationSchemeSettings(walletId); DerivationSchemeSettings derivationScheme = GetDerivationSchemeSettings(walletId);
@@ -658,15 +659,16 @@ namespace BTCPayServer.Controllers
var signingContext = new SigningContextModel() var signingContext = new SigningContextModel()
{ {
PayJoinEndpointUrl = vm.PayJoinEndpointUrl, PayJoinEndpointUrl = vm.PayJoinEndpointUrl,
EnforceLowR = psbt.Suggestions?.ShouldEnforceLowR EnforceLowR = psbt.Suggestions?.ShouldEnforceLowR,
ChangeAddress = psbt.ChangeAddress?.ToString()
}; };
var res = await TryHandleSigningCommands(walletId, psbt.PSBT, command, signingContext, psbt.ChangeAddress); var res = await TryHandleSigningCommands(walletId, psbt.PSBT, command, signingContext);
if (res != null) if (res != null)
{ {
return res; return res;
} }
switch (command) switch (command)
{ {
case "analyze-psbt": case "analyze-psbt":
@@ -681,7 +683,7 @@ namespace BTCPayServer.Controllers
default: default:
return View(vm); return View(vm);
} }
} }
private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network) private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network)
@@ -740,14 +742,12 @@ namespace BTCPayServer.Controllers
ModelState.Clear(); ModelState.Clear();
} }
private IActionResult ViewVault(WalletId walletId, PSBT psbt, SigningContextModel signingContext, PSBT originalPSBT = null) private IActionResult ViewVault(WalletId walletId, SigningContextModel signingContext)
{ {
return View(nameof(WalletSendVault), new WalletSendVaultModel() return View(nameof(WalletSendVault), new WalletSendVaultModel()
{ {
SigningContext = signingContext, SigningContext = signingContext,
WalletId = walletId.ToString(), WalletId = walletId.ToString(),
OriginalPSBT = originalPSBT?.ToBase64(),
PSBT = psbt.ToBase64(),
WebsocketPath = this.Url.Action(nameof(VaultController.VaultBridgeConnection), "Vault", new { walletId = walletId.ToString() }) WebsocketPath = this.Url.Action(nameof(VaultController.VaultBridgeConnection), "Vault", new { walletId = walletId.ToString() })
}); });
} }
@@ -759,8 +759,6 @@ namespace BTCPayServer.Controllers
{ {
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
{ {
PSBT = model.PSBT,
OriginalPSBT = model.OriginalPSBT,
SigningContext = model.SigningContext SigningContext = model.SigningContext
}); });
} }
@@ -772,18 +770,25 @@ namespace BTCPayServer.Controllers
AspAction = nameof(WalletPSBTReady), AspAction = nameof(WalletPSBTReady),
Parameters = Parameters =
{ {
new KeyValuePair<string, string>("psbt", vm.PSBT),
new KeyValuePair<string, string>("originalPsbt", vm.OriginalPSBT),
new KeyValuePair<string, string>("SigningContext.PayJoinEndpointUrl", vm.SigningContext?.PayJoinEndpointUrl),
new KeyValuePair<string, string>("SigningContext.EnforceLowR", vm.SigningContext?.EnforceLowR?.ToString(CultureInfo.InvariantCulture)),
new KeyValuePair<string, string>("SigningKey", vm.SigningKey), new KeyValuePair<string, string>("SigningKey", vm.SigningKey),
new KeyValuePair<string, string>("SigningKeyPath", vm.SigningKeyPath) new KeyValuePair<string, string>("SigningKeyPath", vm.SigningKeyPath)
} }
}; };
AddSigningContext(redirectVm, vm.SigningContext);
return View("PostRedirect", redirectVm); return View("PostRedirect", redirectVm);
} }
private void AddSigningContext(PostRedirectViewModel redirectVm, SigningContextModel signingContext)
{
if (signingContext is null)
return;
redirectVm.Parameters.Add(new KeyValuePair<string, string>("SigningContext.PSBT", signingContext.PSBT));
redirectVm.Parameters.Add(new KeyValuePair<string, string>("SigningContext.OriginalPSBT", signingContext.OriginalPSBT));
redirectVm.Parameters.Add(new KeyValuePair<string, string>("SigningContext.PayJoinEndpointUrl", signingContext.PayJoinEndpointUrl));
redirectVm.Parameters.Add(new KeyValuePair<string, string>("SigningContext.EnforceLowR", signingContext.EnforceLowR?.ToString(CultureInfo.InvariantCulture)));
redirectVm.Parameters.Add(new KeyValuePair<string, string>("SigningContext.ChangeAddress", signingContext.ChangeAddress));
}
private IActionResult RedirectToWalletPSBT(WalletPSBTViewModel vm) private IActionResult RedirectToWalletPSBT(WalletPSBTViewModel vm)
{ {
var redirectVm = new PostRedirectViewModel() var redirectVm = new PostRedirectViewModel()
@@ -793,18 +798,17 @@ namespace BTCPayServer.Controllers
Parameters = Parameters =
{ {
new KeyValuePair<string, string>("psbt", vm.PSBT), new KeyValuePair<string, string>("psbt", vm.PSBT),
new KeyValuePair<string, string>("fileName", vm.FileName), new KeyValuePair<string, string>("fileName", vm.FileName)
new KeyValuePair<string, string>("SigningContext.PayJoinEndpointUrl", vm.SigningContext?.PayJoinEndpointUrl),
new KeyValuePair<string, string>("SigningContext.EnforceLowR", vm.SigningContext?.EnforceLowR?.ToString(CultureInfo.InvariantCulture)),
} }
}; };
AddSigningContext(redirectVm, vm.SigningContext);
return View("PostRedirect", redirectVm); return View("PostRedirect", redirectVm);
} }
void SetAmbientPSBT(PSBT psbt) void SetAmbientPSBT(string psbt)
{ {
if (psbt != null) if (psbt != null)
TempData["AmbientPSBT"] = psbt.ToBase64(); TempData["AmbientPSBT"] = psbt;
else else
TempData.Remove("AmbientPSBT"); TempData.Remove("AmbientPSBT");
} }
@@ -823,17 +827,16 @@ namespace BTCPayServer.Controllers
return null; return null;
} }
private ViewResult ViewWalletSendLedger(WalletId walletId, PSBT psbt, BitcoinAddress hintChange = null) private ViewResult ViewWalletSendLedger(WalletId walletId, SigningContextModel signingContext)
{ {
SetAmbientPSBT(psbt); SetAmbientPSBT(signingContext.PSBT);
return View("WalletSendLedger", new WalletSendLedgerModel() return View("WalletSendLedger", new WalletSendLedgerModel()
{ {
PSBT = psbt.ToBase64(), SigningContext = signingContext,
HintChange = hintChange?.ToString(),
WebsocketPath = this.Url.Action(nameof(LedgerConnection), new { walletId = walletId.ToString() }) WebsocketPath = this.Url.Action(nameof(LedgerConnection), new { walletId = walletId.ToString() })
}); });
} }
[HttpPost] [HttpPost]
[Route("{walletId}/ledger")] [Route("{walletId}/ledger")]
public IActionResult SubmitLedger([ModelBinder(typeof(WalletIdModelBinder))] public IActionResult SubmitLedger([ModelBinder(typeof(WalletIdModelBinder))]
@@ -841,18 +844,17 @@ namespace BTCPayServer.Controllers
{ {
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
{ {
PSBT = model.PSBT SigningContext = model.SigningContext
}); });
} }
[HttpGet("{walletId}/psbt/seed")] [HttpGet("{walletId}/psbt/seed")]
public IActionResult SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))] public IActionResult SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId,string psbt, SigningContextModel signingContext) WalletId walletId, SigningContextModel signingContext)
{ {
return View(nameof(SignWithSeed), new SignWithSeedViewModel() return View(nameof(SignWithSeed), new SignWithSeedViewModel()
{ {
SigningContext = signingContext, SigningContext = signingContext,
PSBT = psbt
}); });
} }
@@ -876,11 +878,11 @@ namespace BTCPayServer.Controllers
"Seed or Key was not in a valid format. It is either the 12/24 words or starts with xprv"); "Seed or Key was not in a valid format. It is either the 12/24 words or starts with xprv");
} }
var psbt = PSBT.Parse(viewModel.PSBT, network.NBitcoinNetwork); var psbt = PSBT.Parse(viewModel.SigningContext.PSBT, network.NBitcoinNetwork);
if (!psbt.IsReadyToSign()) if (!psbt.IsReadyToSign())
{ {
ModelState.AddModelError(nameof(viewModel.PSBT), "PSBT is not ready to be signed"); ModelState.AddModelError(nameof(viewModel.SigningContext.PSBT), "PSBT is not ready to be signed");
} }
if (!ModelState.IsValid) if (!ModelState.IsValid)
@@ -898,7 +900,7 @@ namespace BTCPayServer.Controllers
if (rootedKeyPath == null) if (rootedKeyPath == null)
{ {
ModelState.AddModelError(nameof(viewModel.SeedOrKey), "The master fingerprint and/or account key path of your seed are not set in the wallet settings."); ModelState.AddModelError(nameof(viewModel.SeedOrKey), "The master fingerprint and/or account key path of your seed are not set in the wallet settings.");
return View("SignWithSeed", viewModel); return View(nameof(SignWithSeed), viewModel);
} }
// The user gave the root key, let's try to rebase the PSBT, and derive the account private key // The user gave the root key, let's try to rebase the PSBT, and derive the account private key
if (rootedKeyPath.MasterFingerprint == extKey.GetPublicKey().GetHDFingerPrint()) if (rootedKeyPath.MasterFingerprint == extKey.GetPublicKey().GetHDFingerPrint())
@@ -918,18 +920,17 @@ namespace BTCPayServer.Controllers
ModelState.AddModelError(nameof(viewModel.SeedOrKey), "Impossible to sign the transaction. Probable cause: Incorrect account key path in wallet settings, PSBT already signed."); ModelState.AddModelError(nameof(viewModel.SeedOrKey), "Impossible to sign the transaction. Probable cause: Incorrect account key path in wallet settings, PSBT already signed.");
return View(viewModel); return View(viewModel);
} }
ModelState.Remove(nameof(viewModel.PSBT)); ModelState.Remove(nameof(viewModel.SigningContext.PSBT));
viewModel.SigningContext.PSBT = psbt.ToBase64();
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel() return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
{ {
PSBT = psbt.ToBase64(),
SigningKey = signingKey.GetWif(network.NBitcoinNetwork).ToString(), SigningKey = signingKey.GetWif(network.NBitcoinNetwork).ToString(),
SigningKeyPath = rootedKeyPath?.ToString(), SigningKeyPath = rootedKeyPath?.ToString(),
OriginalPSBT = viewModel.OriginalPSBT,
SigningContext = viewModel.SigningContext SigningContext = viewModel.SigningContext
}); });
} }
private bool PSBTChanged(PSBT psbt, Action act) private bool PSBTChanged(PSBT psbt, Action act)
{ {
var before = psbt.ToBase64(); var before = psbt.ToBase64();
@@ -1271,14 +1272,15 @@ namespace BTCPayServer.Controllers
} }
else if (command == "view-seed" && await CanUseHotWallet()) else if (command == "view-seed" && await CanUseHotWallet())
{ {
var seed = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode) var seed = await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
.GetMetadataAsync<string>(derivationScheme.AccountDerivation, .GetMetadataAsync<string>(derivationScheme.AccountDerivation,
WellknownMetadataKeys.Mnemonic, cancellationToken); WellknownMetadataKeys.Mnemonic, cancellationToken);
if (string.IsNullOrEmpty(seed)) if (string.IsNullOrEmpty(seed))
{ {
TempData.SetStatusMessageModel(new StatusMessageModel() TempData.SetStatusMessageModel(new StatusMessageModel()
{ {
Severity = StatusMessageModel.StatusSeverity.Error, Message = "The seed was not found" Severity = StatusMessageModel.StatusSeverity.Error,
Message = "The seed was not found"
}); });
} }
else else
@@ -1289,7 +1291,7 @@ namespace BTCPayServer.Controllers
Html = $"Please store your seed securely! <br/><code class=\"alert-link\">{seed}</code>" Html = $"Please store your seed securely! <br/><code class=\"alert-link\">{seed}</code>"
}); });
} }
return RedirectToAction(nameof(WalletSettings)); return RedirectToAction(nameof(WalletSettings));
} }
else else

View File

@@ -7,11 +7,10 @@ namespace BTCPayServer.Models.WalletViewModels
{ {
public class SignWithSeedViewModel public class SignWithSeedViewModel
{ {
public string OriginalPSBT { get; set; }
public SigningContextModel SigningContext { get; set; } = new SigningContextModel(); public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
[Required] [Required]
public string PSBT { get; set; } [Display(Name = "BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)")]
[Required][Display(Name = "BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)")]
public string SeedOrKey { get; set; } public string SeedOrKey { get; set; }
[Display(Name = "Optional seed passphrase")] [Display(Name = "Optional seed passphrase")]

View File

@@ -7,7 +7,10 @@ namespace BTCPayServer.Models.WalletViewModels
{ {
public class SigningContextModel public class SigningContextModel
{ {
public string PSBT { get; set; }
public string OriginalPSBT { get; set; }
public string PayJoinEndpointUrl { get; set; } public string PayJoinEndpointUrl { get; set; }
public bool? EnforceLowR { get; set; } public bool? EnforceLowR { get; set; }
public string ChangeAddress { get; set; }
} }
} }

View File

@@ -9,8 +9,6 @@ namespace BTCPayServer.Models.WalletViewModels
public class WalletPSBTReadyViewModel public class WalletPSBTReadyViewModel
{ {
public SigningContextModel SigningContext { get; set; } = new SigningContextModel(); public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
public string OriginalPSBT { get; set; }
public string PSBT { get; set; }
public string SigningKey { get; set; } public string SigningKey { get; set; }
public string SigningKeyPath { get; set; } public string SigningKeyPath { get; set; }
public string GlobalError { get; set; } public string GlobalError { get; set; }

View File

@@ -8,7 +8,6 @@ namespace BTCPayServer.Models.WalletViewModels
public class WalletSendLedgerModel public class WalletSendLedgerModel
{ {
public string WebsocketPath { get; set; } public string WebsocketPath { get; set; }
public string PSBT { get; set; } public SigningContextModel SigningContext { get; set; }
public string HintChange { get; set; }
} }
} }

View File

@@ -7,9 +7,7 @@ namespace BTCPayServer.Models.WalletViewModels
{ {
public class WalletSendVaultModel public class WalletSendVaultModel
{ {
public string OriginalPSBT { get; set; }
public string WalletId { get; set; } public string WalletId { get; set; }
public string PSBT { get; set; }
public string WebsocketPath { get; set; } public string WebsocketPath { get; set; }
public SigningContextModel SigningContext { get; set; } = new SigningContextModel(); public SigningContextModel SigningContext { get; set; } = new SigningContextModel();
} }

View File

@@ -27,10 +27,7 @@
<div class="col-md-10"> <div class="col-md-10">
<div asp-validation-summary="All" class="text-danger"></div> <div asp-validation-summary="All" class="text-danger"></div>
<form method="post" asp-action="SignWithSeed" asp-route-walletId="@this.Context.GetRouteValue("walletId")"> <form method="post" asp-action="SignWithSeed" asp-route-walletId="@this.Context.GetRouteValue("walletId")">
<input type="hidden" asp-for="OriginalPSBT" /> <partial name="SigningContext" for="SigningContext" />
<input type="hidden" asp-for="PSBT" />
<input type="hidden" asp-for="SigningContext.PayJoinEndpointUrl" />
<input type="hidden" asp-for="SigningContext.EnforceLowR" />
<div class="form-group"> <div class="form-group">
<label asp-for="SeedOrKey"></label> <label asp-for="SeedOrKey"></label>
<input asp-for="SeedOrKey" class="form-control" /> <input asp-for="SeedOrKey" class="form-control" />

View File

@@ -30,8 +30,7 @@
<div class="form-group"> <div class="form-group">
<form method="post" asp-action="WalletPSBT" asp-route-walletId="@this.Context.GetRouteValue("walletId")"> <form method="post" asp-action="WalletPSBT" asp-route-walletId="@this.Context.GetRouteValue("walletId")">
<input type="hidden" asp-for="CryptoCode" /> <input type="hidden" asp-for="CryptoCode" />
<input type="hidden" asp-for="SigningContext.PayJoinEndpointUrl" /> <partial name="SigningContext" for="SigningContext" />
<input type="hidden" asp-for="SigningContext.EnforceLowR" />
<input type="hidden" asp-for="NBXSeedAvailable" /> <input type="hidden" asp-for="NBXSeedAvailable" />
<input type="hidden" asp-for="PSBT" /> <input type="hidden" asp-for="PSBT" />
<input type="hidden" asp-for="FileName" /> <input type="hidden" asp-for="FileName" />

View File

@@ -137,12 +137,9 @@
<div class="row"> <div class="row">
<div class="col-lg-12 text-center"> <div class="col-lg-12 text-center">
<form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@this.Context.GetRouteValue("walletId")"> <form method="post" asp-action="WalletPSBTReady" asp-route-walletId="@this.Context.GetRouteValue("walletId")">
<input type="hidden" asp-for="PSBT" value="@Model.PSBT" />
<input type="hidden" asp-for="OriginalPSBT" />
<input type="hidden" asp-for="SigningKey" /> <input type="hidden" asp-for="SigningKey" />
<input type="hidden" asp-for="SigningKeyPath" /> <input type="hidden" asp-for="SigningKeyPath" />
<input type="hidden" asp-for="SigningContext.PayJoinEndpointUrl" /> <partial name="SigningContext" for="SigningContext" />
<input type="hidden" asp-for="SigningContext.EnforceLowR" />
@if (!Model.HasErrors) @if (!Model.HasErrors)
{ {
@if (!string.IsNullOrEmpty(Model.SigningContext?.PayJoinEndpointUrl)) @if (!string.IsNullOrEmpty(Model.SigningContext?.PayJoinEndpointUrl))

View File

@@ -21,8 +21,7 @@
<div class="row"> <div class="row">
<div class="col-md-10"> <div class="col-md-10">
<form id="broadcastForm" asp-action="SubmitLedger" asp-route-walletId="@this.Context.GetRouteValue("walletId")" method="post" style="display:none;"> <form id="broadcastForm" asp-action="SubmitLedger" asp-route-walletId="@this.Context.GetRouteValue("walletId")" method="post" style="display:none;">
<input type="hidden" id="PSBT" asp-for="PSBT" value="@Model.PSBT"/> <partial name="SigningContext" for="SigningContext" />
<input type="hidden" asp-for="HintChange" />
<input type="hidden" asp-for="WebsocketPath" /> <input type="hidden" asp-for="WebsocketPath" />
</form> </form>
<p> <p>

View File

@@ -22,11 +22,8 @@
<div id="body" class="col-md-10"> <div id="body" class="col-md-10">
<form id="broadcastForm" asp-action="WalletSendVault" asp-route-walletId="@this.Context.GetRouteValue("walletId")" method="post" style="display:none;"> <form id="broadcastForm" asp-action="WalletSendVault" asp-route-walletId="@this.Context.GetRouteValue("walletId")" method="post" style="display:none;">
<input type="hidden" id="WalletId" asp-for="WalletId" /> <input type="hidden" id="WalletId" asp-for="WalletId" />
<input type="hidden" id="PSBT" asp-for="PSBT" value="@Model.PSBT" />
<input type="hidden" id="OriginalPSBT" asp-for="OriginalPSBT" value="@Model.OriginalPSBT" />
<input type="hidden" asp-for="WebsocketPath" /> <input type="hidden" asp-for="WebsocketPath" />
<input type="hidden" asp-for="SigningContext.PayJoinEndpointUrl" /> <partial name="SigningContext" for="SigningContext" />
<input type="hidden" asp-for="SigningContext.EnforceLowR" />
</form> </form>
<div id="vaultPlaceholder"></div> <div id="vaultPlaceholder"></div>
<button id="vault-confirm" class="btn btn-primary" style="display:none;"></button> <button id="vault-confirm" class="btn btn-primary" style="display:none;"></button>
@@ -52,13 +49,12 @@
ws_uri += websocketPath; ws_uri += websocketPath;
var html = $("#VaultConnection").html(); var html = $("#VaultConnection").html();
$("#vaultPlaceholder").html(html); $("#vaultPlaceholder").html(html);
var vaultUI = new vaultui.VaultBridgeUI(ws_uri); var vaultUI = new vaultui.VaultBridgeUI(ws_uri);
if (await vaultUI.askForDevice() && await vaultUI.askSignPSBT({ if (await vaultUI.askForDevice() && await vaultUI.askSignPSBT({
walletId: $("#WalletId").val(), walletId: $("#WalletId").val(),
psbt: $("#PSBT").val() psbt: $("#SigningContext_PSBT").val()
})) { })) {
$("#PSBT").val(vaultUI.psbt); $("#SigningContext_PSBT").val(vaultUI.psbt);
$("#broadcastForm").submit(); $("#broadcastForm").submit();
} }
} }

View File

@@ -1,6 +1,6 @@
$(function () { $(function () {
var psbt = $("#PSBT").val(); var psbt = $("#PSBT").val();
var hintChange = $("#HintChange").val(); var hintChange = $("#SigningContext_ChangeAddress").val();
var websocketPath = $("#WebsocketPath").val(); var websocketPath = $("#WebsocketPath").val();
var loc = window.location, ws_uri; var loc = window.location, ws_uri;
@@ -38,7 +38,6 @@
return false; return false;
$(".crypto-info").css("display", "block"); $(".crypto-info").css("display", "block");
var args = ""; var args = "";
args += "&psbt=" + encodeURIComponent(psbt);
args += "&hintChange=" + encodeURIComponent(hintChange); args += "&hintChange=" + encodeURIComponent(hintChange);
WriteAlert("warning", 'Please validate the transaction on your ledger'); WriteAlert("warning", 'Please validate the transaction on your ledger');
@@ -61,7 +60,7 @@
if (result.error) { if (result.error) {
WriteAlert("danger", result.error); WriteAlert("danger", result.error);
} else { } else {
$("#PSBT").val(result.psbt); $("#SigningContext_PSBT").val(result.psbt);
$("#broadcastForm").submit(); $("#broadcastForm").submit();
} }
}); });