Vault: Allow user to pick the account number

This commit is contained in:
nicolas.dorier 2019-12-04 15:54:08 +09:00
parent ea5bd6d435
commit 50e7d8389c
No known key found for this signature in database
GPG Key ID: 6618763EF09186FE
4 changed files with 107 additions and 62 deletions

View File

@ -193,39 +193,63 @@ namespace BTCPayServer.Controllers
continue;
}
break;
case "ask-xpubs":
case "ask-xpub":
if (await RequireDeviceUnlocking())
{
continue;
}
var askedXpub = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken));
var addressType = askedXpub["addressType"].Value<string>();
var accountNumber = askedXpub["accountNumber"].Value<int>();
JObject result = new JObject();
var factory = network.NBXplorerNetwork.DerivationStrategyFactory;
var keyPath = new KeyPath("84'").Derive(network.CoinType).Derive(0, true);
BitcoinExtPubKey xpub = await device.GetXPubAsync(keyPath);
if (fingerprint is null)
{
fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint;
}
result["fingerprint"] = fingerprint.Value.ToString();
var strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
DerivationStrategyBase strategy = null;
KeyPath keyPath = null;
BitcoinExtPubKey xpub = null;
if (!network.NBitcoinNetwork.Consensus.SupportSegwit && addressType != "legacy")
{
ScriptPubKeyType = ScriptPubKeyType.Segwit
});
AddDerivationSchemeToJson("segwit", result, keyPath, xpub, strategy);
keyPath = new KeyPath("49'").Derive(network.CoinType).Derive(0, true);
xpub = await device.GetXPubAsync(keyPath);
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
await websocketHelper.Send("{ \"error\": \"segwit-notsupported\"}", cancellationToken);
continue;
}
if (addressType == "segwit")
{
ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH
});
AddDerivationSchemeToJson("segwitWrapped", result, keyPath, xpub, strategy);
keyPath = new KeyPath("44'").Derive(network.CoinType).Derive(0, true);
xpub = await device.GetXPubAsync(keyPath);
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
keyPath = new KeyPath("84'").Derive(network.CoinType).Derive(accountNumber, true);
xpub = await device.GetXPubAsync(keyPath);
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
{
ScriptPubKeyType = ScriptPubKeyType.Segwit
});
}
if (addressType == "segwitWrapped")
{
ScriptPubKeyType = ScriptPubKeyType.Legacy
});
AddDerivationSchemeToJson("legacy", result, keyPath, xpub, strategy);
keyPath = new KeyPath("49'").Derive(network.CoinType).Derive(accountNumber, true);
xpub = await device.GetXPubAsync(keyPath);
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
{
ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH
});
}
else if (addressType == "legacy")
{
keyPath = new KeyPath("44'").Derive(network.CoinType).Derive(accountNumber, true);
xpub = await device.GetXPubAsync(keyPath);
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
{
ScriptPubKeyType = ScriptPubKeyType.Legacy
});
}
result.Add(new JProperty("strategy", strategy.ToString()));
result.Add(new JProperty("accountKey", xpub.ToString()));
result.Add(new JProperty("keyPath", keyPath.ToString()));
await websocketHelper.Send(result.ToString(), cancellationToken);
break;
case "ask-device":
@ -296,15 +320,5 @@ namespace BTCPayServer.Controllers
.FirstOrDefault(p => p.PaymentId.PaymentType == Payments.PaymentTypes.BTCLike && p.PaymentId.CryptoCode == walletId.CryptoCode);
return paymentMethod;
}
private void AddDerivationSchemeToJson(string propertyName, JObject result, KeyPath keyPath, BitcoinExtPubKey xpub, DerivationStrategyBase strategy)
{
result.Add(new JProperty(propertyName, new JObject()
{
new JProperty("strategy", strategy.ToString()),
new JProperty("accountKey", xpub.ToString()),
new JProperty("keyPath", keyPath.ToString()),
}));
}
}
}

View File

@ -92,22 +92,31 @@
</div>
<div class="modal-body">
<p>You may import from BTCPayServer Vault.</p>
<div id="vaultPlaceholder"></div>
<div class="form-group">
<div id="vaultPlaceholder"></div>
</div>
<div id="vault-xpub" style="display:none;">
<div class="form-group">
<label for="addressType">Address type</label>
<select name="addressType" class="form-control">
<option value="segwit">Segwit (Recommended, cheapest transaction fee)</option>
<option value="segwitWrapped">Segwit wrapped (less cheap but compatible with old wallets)</option>
<option value="legacy">Legacy (Not recommended)</option>
</select>
</div>
<div class="form-group">
<label for="accountNumber">Account</label>
<select name="accountNumber" class="form-control">
@for (int i = 0; i < 20; i++)
{
<option value="@i">@i</option>
}
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<div id="vault-dropdown" style="display:none;" class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select the type of address you want
</button>
<div class="dropdown-menu overflow-auto" style="max-height: 200px;">
<a class="dropdown-item" href="#" id="vault-segwit">Segwit (Recommended, cheapest transaction fee)</a>
<a class="dropdown-item" href="#" id="vault-segwitWrapped">Segwit wrapped (less cheap but compatible with old wallets)</a>
<a class="dropdown-item" href="#" id="vault-legacy">Legacy (Not recommended)</a>
</div>
</div>
<button id="vault-confirm" class="btn btn-primary" style="display:none;"></button>
</div>
</form>

View File

@ -112,20 +112,15 @@ $(document).ready(function () {
ws_uri += "//" + loc.host;
ws_uri += websocketPath;
function displayXPubs(xpubs) {
$("#vault-dropdown").css("display", "block");
$("#vault-dropdown .dropdown-item").click(function () {
var id = $(this).attr('id').replace("vault-", "");
var xpub = xpubs[id];
$("#DerivationScheme").val(xpub.strategy);
$("#RootFingerprint").val(xpubs.fingerprint);
$("#AccountKey").val(xpub.accountKey);
$("#Source").val("Vault");
$("#DerivationSchemeFormat").val("BTCPay");
$("#KeyPath").val(xpub.keyPath);
$(".modal").modal('hide');
$(".hw-fields").show();
});
function displayXPubs(xpub) {
$("#DerivationScheme").val(xpub.strategy);
$("#RootFingerprint").val(xpub.fingerprint);
$("#AccountKey").val(xpub.accountKey);
$("#Source").val("Vault");
$("#DerivationSchemeFormat").val("BTCPay");
$("#KeyPath").val(xpub.keyPath);
$(".modal").modal('hide');
$(".hw-fields").show();
}
var vaultInit = false;
@ -138,8 +133,8 @@ $(document).ready(function () {
$("#vaultPlaceholder").html(html);
var vaultUI = new vaultui.VaultBridgeUI(ws_uri);
if (await vaultUI.askForXPubs()) {
displayXPubs(vaultUI.xpubs);
if (await vaultUI.askForDevice() && await vaultUI.askForXPubs()) {
displayXPubs(vaultUI.xpub);
}
});
});

View File

@ -37,6 +37,7 @@ var vaultui = (function () {
fetchingDevice: new VaultFeedback("?", "Fetching device...", "vault-feedback2", "fetching-device"),
deviceFound: new VaultFeedback("ok", "Device found: {{0}}", "vault-feedback2", "device-selected"),
fetchingXpubs: new VaultFeedback("?", "Fetching public keys...", "vault-feedback3", "fetching-xpubs"),
askXpubs: new VaultFeedback("?", "Select your address type and account", "vault-feedback3", "fetching-xpubs"),
fetchedXpubs: new VaultFeedback("ok", "Public keys successfully fetched.", "vault-feedback3", "xpubs-fetched"),
unexpectedError: new VaultFeedback("failed", "An unexpected error happened.", "vault-feedback3", "unknown-error"),
invalidNetwork: new VaultFeedback("failed", "The device is targetting a different chain.", "vault-feedback3", "invalid-network"),
@ -69,7 +70,7 @@ var vaultui = (function () {
*/
this.psbt = null;
this.xpubs = null;
this.xpub = null;
/**
* @param {VaultFeedback} feedback
*/
@ -172,8 +173,10 @@ var vaultui = (function () {
this.askForXPubs = async function () {
if (!await self.ensureConnectedToBackend())
return false;
self.bridge.socket.send("ask-xpub");
var selectedXPubs = await self.getXpubSettings();
self.bridge.socket.send(JSON.stringify(selectedXPubs));
show(VaultFeedbacks.fetchingXpubs);
self.bridge.socket.send("ask-xpubs");
var json = await self.bridge.waitBackendMessage();
if (json.hasOwnProperty("error")) {
if (await needRetry(json))
@ -181,10 +184,33 @@ var vaultui = (function () {
return false;
}
show(VaultFeedbacks.fetchedXpubs);
self.xpubs = json;
self.xpub = json;
return true;
};
/**
* @returns {Promise<{addressType:string, accountNumber:number}>}
*/
this.getXpubSettings = function () {
show(VaultFeedbacks.askXpubs);
$("#vault-xpub").css("display", "block");
$("#vault-confirm").css("display", "block");
$("#vault-confirm").text("Confirm");
return new Promise(function (resolve, reject) {
var pinCode = "";
$("#vault-confirm").click(async function (e) {
e.preventDefault();
$("#vault-xpub").css("display", "none");
$("#vault-confirm").css("display", "none");
$(this).unbind();
resolve({
addressType: $("select[name=\"addressType\"]").val(),
accountNumber: parseInt($("select[name=\"accountNumber\"]").val())
});
});
});
};
/**
* @returns {Promise<string>}
*/
@ -195,7 +221,8 @@ var vaultui = (function () {
$("#vault-confirm").text("Confirm the pin code");
return new Promise(function (resolve, reject) {
var pinCode = "";
$("#vault-confirm").click(async function () {
$("#vault-confirm").click(async function (e) {
e.preventDefault();
$("#pin-input").css("display", "none");
$("#vault-confirm").css("display", "none");
$(this).unbind();