mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Refactor common data structure for wallet into SigningContext
This commit is contained in:
@@ -97,7 +97,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
// Borrowed from https://github.com/ManageIQ/guides/blob/master/labels.md
|
||||
string[] LabelColorScheme = new string[]
|
||||
string[] LabelColorScheme = new string[]
|
||||
{
|
||||
"#fbca04",
|
||||
"#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
|
||||
// does not work
|
||||
[ModelBinder(typeof(WalletIdModelBinder))]
|
||||
WalletId walletId, string transactionId,
|
||||
string addlabel = null,
|
||||
WalletId walletId, string transactionId,
|
||||
string addlabel = null,
|
||||
string addlabelclick = null,
|
||||
string addcomment = null,
|
||||
string addcomment = null,
|
||||
string removelabel = null)
|
||||
{
|
||||
addlabel = addlabel ?? addlabelclick;
|
||||
@@ -135,7 +135,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
catch { }
|
||||
/////////
|
||||
|
||||
|
||||
DerivationSchemeSettings paymentMethod = GetDerivationSchemeSettings(walletId);
|
||||
if (paymentMethod == null)
|
||||
return NotFound();
|
||||
@@ -147,7 +147,7 @@ namespace BTCPayServer.Controllers
|
||||
var walletTransactionsInfo = await walletTransactionsInfoAsync;
|
||||
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);
|
||||
if (!walletTransactionsInfo.TryGetValue(transactionId, out var walletTransactionInfo))
|
||||
{
|
||||
@@ -290,7 +290,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
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);
|
||||
model.Labels.AddRange(labels);
|
||||
vm.Comment = transactionInfo.Comment;
|
||||
@@ -359,7 +359,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
var address = cachedAddress.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork);
|
||||
ExplorerClientProvider.GetExplorerClient(network)
|
||||
.CancelReservation(cachedAddress.DerivationStrategy, new[] {cachedAddress.KeyPath});
|
||||
.CancelReservation(cachedAddress.DerivationStrategy, new[] { cachedAddress.KeyPath });
|
||||
this.TempData.SetStatusMessageModel(new StatusMessageModel()
|
||||
{
|
||||
AllowDismiss = true,
|
||||
@@ -373,7 +373,7 @@ namespace BTCPayServer.Controllers
|
||||
_WalletReceiveStateService.Set(walletId, reserve);
|
||||
break;
|
||||
}
|
||||
return RedirectToAction(nameof(WalletReceive), new {walletId});
|
||||
return RedirectToAction(nameof(WalletReceive), new { walletId });
|
||||
}
|
||||
|
||||
private async Task<bool> CanUseHotWallet()
|
||||
@@ -384,7 +384,7 @@ namespace BTCPayServer.Controllers
|
||||
var policies = await _settingsRepository.GetSettingAsync<PoliciesSettings>();
|
||||
return policies?.AllowHotWalletForAll is true;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[Route("{walletId}/send")]
|
||||
public async Task<IActionResult> WalletSend(
|
||||
@@ -405,7 +405,7 @@ namespace BTCPayServer.Controllers
|
||||
rateRules.Spread = 0.0m;
|
||||
var currencyPair = new Rating.CurrencyPair(paymentMethod.PaymentId.CryptoCode, GetCurrencyCode(storeData.DefaultLang) ?? "USD");
|
||||
double.TryParse(defaultAmount, out var amount);
|
||||
var model = new WalletSendModel()
|
||||
var model = new WalletSendModel()
|
||||
{
|
||||
Outputs = new List<WalletSendModel.TransactionOutput>()
|
||||
{
|
||||
@@ -417,11 +417,11 @@ namespace BTCPayServer.Controllers
|
||||
},
|
||||
CryptoCode = walletId.CryptoCode
|
||||
};
|
||||
if (!string.IsNullOrEmpty(bip21))
|
||||
{
|
||||
LoadFromBIP21(model, bip21, network);
|
||||
}
|
||||
var feeProvider = _feeRateProvider.CreateFeeProvider(network);
|
||||
if (!string.IsNullOrEmpty(bip21))
|
||||
{
|
||||
LoadFromBIP21(model, bip21, network);
|
||||
}
|
||||
var feeProvider = _feeRateProvider.CreateFeeProvider(network);
|
||||
var recommendedFees =
|
||||
new[]
|
||||
{
|
||||
@@ -433,7 +433,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
var result = await feeProvider.GetFeeRateAsync(
|
||||
(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)
|
||||
{
|
||||
@@ -446,7 +446,7 @@ namespace BTCPayServer.Controllers
|
||||
.GetMetadataAsync<string>(GetDerivationSchemeSettings(walletId).AccountDerivation,
|
||||
WellknownMetadataKeys.MasterHDKey));
|
||||
model.CurrentBalance = await balance;
|
||||
|
||||
|
||||
await Task.WhenAll(recommendedFees);
|
||||
model.RecommendedSatoshiPerByte =
|
||||
recommendedFees.Select(tuple => tuple.Result).Where(option => option != null).ToList();
|
||||
@@ -474,7 +474,7 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[Route("{walletId}/send")]
|
||||
@@ -498,11 +498,11 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
LoadFromBIP21(vm, bip21, network);
|
||||
}
|
||||
|
||||
decimal transactionAmountSum = 0;
|
||||
|
||||
decimal transactionAmountSum = 0;
|
||||
if (command == "toggle-input-selection")
|
||||
{
|
||||
vm.InputSelection = !vm.InputSelection;
|
||||
vm.InputSelection = !vm.InputSelection;
|
||||
}
|
||||
if (vm.InputSelection)
|
||||
{
|
||||
@@ -510,7 +510,7 @@ namespace BTCPayServer.Controllers
|
||||
var walletBlobAsync = await WalletRepository.GetWalletInfo(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 =>
|
||||
{
|
||||
walletTransactionsInfoAsync.TryGetValue(coin.OutPoint.Hash.ToString(), out var info);
|
||||
@@ -519,7 +519,7 @@ namespace BTCPayServer.Controllers
|
||||
Outpoint = coin.OutPoint.ToString(),
|
||||
Amount = coin.Value.GetValue(network),
|
||||
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())
|
||||
};
|
||||
}).ToArray();
|
||||
@@ -544,7 +544,7 @@ namespace BTCPayServer.Controllers
|
||||
if (command.StartsWith("remove-output", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
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);
|
||||
return View(vm);
|
||||
}
|
||||
@@ -569,12 +569,12 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork);
|
||||
BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork);
|
||||
}
|
||||
catch
|
||||
{
|
||||
var inputName =
|
||||
string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) +
|
||||
var inputName =
|
||||
string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) +
|
||||
nameof(transactionOutput.DestinationAddress);
|
||||
|
||||
ModelState.AddModelError(inputName, "Invalid address");
|
||||
@@ -599,7 +599,8 @@ namespace BTCPayServer.Controllers
|
||||
vm.AddModelError(model => model.Outputs[subtractFeesOutput].SubtractFeesFromOutput,
|
||||
"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,
|
||||
"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);
|
||||
|
||||
DerivationSchemeSettings derivationScheme = GetDerivationSchemeSettings(walletId);
|
||||
@@ -658,15 +659,16 @@ namespace BTCPayServer.Controllers
|
||||
var signingContext = new SigningContextModel()
|
||||
{
|
||||
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)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "analyze-psbt":
|
||||
@@ -681,7 +683,7 @@ namespace BTCPayServer.Controllers
|
||||
default:
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void LoadFromBIP21(WalletSendModel vm, string bip21, BTCPayNetwork network)
|
||||
@@ -740,14 +742,12 @@ namespace BTCPayServer.Controllers
|
||||
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()
|
||||
{
|
||||
SigningContext = signingContext,
|
||||
WalletId = walletId.ToString(),
|
||||
OriginalPSBT = originalPSBT?.ToBase64(),
|
||||
PSBT = psbt.ToBase64(),
|
||||
WebsocketPath = this.Url.Action(nameof(VaultController.VaultBridgeConnection), "Vault", new { walletId = walletId.ToString() })
|
||||
});
|
||||
}
|
||||
@@ -759,8 +759,6 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
|
||||
{
|
||||
PSBT = model.PSBT,
|
||||
OriginalPSBT = model.OriginalPSBT,
|
||||
SigningContext = model.SigningContext
|
||||
});
|
||||
}
|
||||
@@ -772,18 +770,25 @@ namespace BTCPayServer.Controllers
|
||||
AspAction = nameof(WalletPSBTReady),
|
||||
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>("SigningKeyPath", vm.SigningKeyPath)
|
||||
}
|
||||
};
|
||||
|
||||
AddSigningContext(redirectVm, vm.SigningContext);
|
||||
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)
|
||||
{
|
||||
var redirectVm = new PostRedirectViewModel()
|
||||
@@ -793,18 +798,17 @@ namespace BTCPayServer.Controllers
|
||||
Parameters =
|
||||
{
|
||||
new KeyValuePair<string, string>("psbt", vm.PSBT),
|
||||
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)),
|
||||
new KeyValuePair<string, string>("fileName", vm.FileName)
|
||||
}
|
||||
};
|
||||
AddSigningContext(redirectVm, vm.SigningContext);
|
||||
return View("PostRedirect", redirectVm);
|
||||
}
|
||||
|
||||
void SetAmbientPSBT(PSBT psbt)
|
||||
void SetAmbientPSBT(string psbt)
|
||||
{
|
||||
if (psbt != null)
|
||||
TempData["AmbientPSBT"] = psbt.ToBase64();
|
||||
TempData["AmbientPSBT"] = psbt;
|
||||
else
|
||||
TempData.Remove("AmbientPSBT");
|
||||
}
|
||||
@@ -823,17 +827,16 @@ namespace BTCPayServer.Controllers
|
||||
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()
|
||||
{
|
||||
PSBT = psbt.ToBase64(),
|
||||
HintChange = hintChange?.ToString(),
|
||||
SigningContext = signingContext,
|
||||
WebsocketPath = this.Url.Action(nameof(LedgerConnection), new { walletId = walletId.ToString() })
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[Route("{walletId}/ledger")]
|
||||
public IActionResult SubmitLedger([ModelBinder(typeof(WalletIdModelBinder))]
|
||||
@@ -841,18 +844,17 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
|
||||
{
|
||||
PSBT = model.PSBT
|
||||
SigningContext = model.SigningContext
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{walletId}/psbt/seed")]
|
||||
public IActionResult SignWithSeed([ModelBinder(typeof(WalletIdModelBinder))]
|
||||
WalletId walletId,string psbt, SigningContextModel signingContext)
|
||||
WalletId walletId, SigningContextModel signingContext)
|
||||
{
|
||||
return View(nameof(SignWithSeed), new SignWithSeedViewModel()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
var psbt = PSBT.Parse(viewModel.PSBT, network.NBitcoinNetwork);
|
||||
var psbt = PSBT.Parse(viewModel.SigningContext.PSBT, network.NBitcoinNetwork);
|
||||
|
||||
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)
|
||||
@@ -898,7 +900,7 @@ namespace BTCPayServer.Controllers
|
||||
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.");
|
||||
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
|
||||
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.");
|
||||
return View(viewModel);
|
||||
}
|
||||
ModelState.Remove(nameof(viewModel.PSBT));
|
||||
ModelState.Remove(nameof(viewModel.SigningContext.PSBT));
|
||||
viewModel.SigningContext.PSBT = psbt.ToBase64();
|
||||
return RedirectToWalletPSBTReady(new WalletPSBTReadyViewModel()
|
||||
{
|
||||
PSBT = psbt.ToBase64(),
|
||||
SigningKey = signingKey.GetWif(network.NBitcoinNetwork).ToString(),
|
||||
SigningKeyPath = rootedKeyPath?.ToString(),
|
||||
OriginalPSBT = viewModel.OriginalPSBT,
|
||||
SigningContext = viewModel.SigningContext
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private bool PSBTChanged(PSBT psbt, Action act)
|
||||
{
|
||||
var before = psbt.ToBase64();
|
||||
@@ -1271,14 +1272,15 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
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,
|
||||
WellknownMetadataKeys.Mnemonic, cancellationToken);
|
||||
if (string.IsNullOrEmpty(seed))
|
||||
{
|
||||
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
|
||||
@@ -1289,7 +1291,7 @@ namespace BTCPayServer.Controllers
|
||||
Html = $"Please store your seed securely! <br/><code class=\"alert-link\">{seed}</code>"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return RedirectToAction(nameof(WalletSettings));
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user