Fix the PSBT signing flow (#3465)

This commit is contained in:
Nicolas Dorier
2022-02-17 17:58:56 +09:00
committed by GitHub
parent dcdab5b218
commit 6efeb60c41
11 changed files with 199 additions and 179 deletions

View File

@@ -146,17 +146,22 @@ namespace BTCPayServer.Controllers
WalletId walletId, WalletPSBTViewModel vm, string returnUrl = null, string command = null)
{
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
var psbt = await vm.GetPSBT(network.NBitcoinNetwork);
vm.SigningContext.PSBT ??= psbt.ToBase64();
if (returnUrl is null)
returnUrl = Url.Action(nameof(WalletTransactions), new { walletId });
var psbt = await vm.GetPSBT(network.NBitcoinNetwork);
if (psbt is null || vm.InvalidPSBT)
{
ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT");
return View("WalletSigningOptions", new WalletSigningOptionsModel(vm.SigningContext, returnUrl));
}
switch (command)
{
case "vault":
return ViewVault(walletId, vm.SigningContext);
case "seed":
return SignWithSeed(walletId, vm.SigningContext);
case "decode":
return await WalletPSBT(walletId, vm, "decode");
default:
break;
}
@@ -171,7 +176,7 @@ namespace BTCPayServer.Controllers
WellknownMetadataKeys.MasterHDKey);
if (extKey != null)
{
return SignWithSeed(walletId,
return await SignWithSeed(walletId,
new SignWithSeedViewModel { SeedOrKey = extKey, SigningContext = vm.SigningContext });
}
}
@@ -181,26 +186,16 @@ namespace BTCPayServer.Controllers
[HttpGet("{walletId}/psbt")]
public async Task<IActionResult> WalletPSBT([ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, WalletPSBTViewModel vm)
WalletId walletId)
{
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
var vm = new WalletPSBTViewModel();
vm.CryptoCode = network.CryptoCode;
var derivationSchemeSettings = GetDerivationSchemeSettings(walletId);
if (derivationSchemeSettings == null)
return NotFound();
vm.NBXSeedAvailable = await CanUseHotWallet() && derivationSchemeSettings.IsHotWallet;
if (await vm.GetPSBT(network.NBitcoinNetwork) is PSBT psbt)
{
vm.PSBT = vm.SigningContext.PSBT = psbt.ToBase64();
vm.PSBTHex = psbt.ToHex();
vm.Decoded = psbt.ToString();
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
return View("WalletPSBTDecoded", vm);
}
return View(vm);
}
@@ -208,10 +203,8 @@ namespace BTCPayServer.Controllers
public async Task<IActionResult> WalletPSBT(
[ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId,
WalletPSBTViewModel vm, string command = null)
WalletPSBTViewModel vm, string command)
{
if (command == null)
return await WalletPSBT(walletId, vm);
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
vm.CryptoCode = network.CryptoCode;
@@ -221,25 +214,23 @@ namespace BTCPayServer.Controllers
vm.NBXSeedAvailable = await CanUseHotWallet() && derivationSchemeSettings.IsHotWallet;
var psbt = await vm.GetPSBT(network.NBitcoinNetwork);
if (psbt == null)
if (vm.InvalidPSBT)
{
ModelState.AddModelError(nameof(vm.PSBT), "Invalid PSBT");
return View(vm);
}
vm.PSBT = psbt.ToBase64();
vm.PSBTHex = psbt.ToHex();
if (psbt is null)
{
return View("WalletPSBT", vm);
}
switch (command)
{
case "sign":
return await WalletSign(walletId, vm, nameof(WalletPSBT));
return await WalletSign(walletId, vm);
case "decode":
ModelState.Remove(nameof(vm.PSBT));
ModelState.Remove(nameof(vm.FileName));
ModelState.Remove(nameof(vm.UploadedPSBTFile));
vm.PSBT = vm.SigningContext.PSBT;
vm.PSBTHex = psbt.ToHex();
vm.Decoded = psbt.ToString();
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
return View("WalletPSBTDecoded", vm);
@@ -273,8 +264,7 @@ namespace BTCPayServer.Controllers
}
default:
var viewName = string.IsNullOrEmpty(vm.PSBT) ? "WalletPSBT" : "WalletPSBTDecoded";
return View(viewName, vm);
return View("WalletPSBTDecoded", vm);
}
}
@@ -393,28 +383,21 @@ namespace BTCPayServer.Controllers
[HttpPost("{walletId}/psbt/ready")]
public async Task<IActionResult> WalletPSBTReady(
[ModelBinder(typeof(WalletIdModelBinder))]
WalletId walletId, WalletPSBTViewModel vm, string command = null, CancellationToken cancellationToken = default)
WalletId walletId, WalletPSBTViewModel vm, string command, CancellationToken cancellationToken = default)
{
if (command == null)
return await WalletPSBT(walletId, vm);
PSBT psbt;
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
DerivationSchemeSettings derivationSchemeSettings;
try
PSBT psbt = await vm.GetPSBT(network.NBitcoinNetwork);
if (vm.InvalidPSBT || psbt is null)
{
psbt = PSBT.Parse(vm.SigningContext.PSBT, network.NBitcoinNetwork);
derivationSchemeSettings = GetDerivationSchemeSettings(walletId);
if (derivationSchemeSettings == null)
return NotFound();
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
}
catch
{
vm.GlobalError = "Invalid PSBT";
if (vm.InvalidPSBT)
vm.GlobalError = "Invalid PSBT";
return View(nameof(WalletPSBT), vm);
}
DerivationSchemeSettings derivationSchemeSettings = GetDerivationSchemeSettings(walletId);
if (derivationSchemeSettings == null)
return NotFound();
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
switch (command)
{
@@ -543,6 +526,9 @@ namespace BTCPayServer.Controllers
{
PSBT = psbt.ToBase64()
});
case "decode":
await FetchTransactionDetails(derivationSchemeSettings, vm, network);
return View("WalletPSBTDecoded", vm);
default:
vm.GlobalError = "Unknown command";
return View(nameof(WalletPSBT), vm);