2018-02-25 16:48:12 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net.WebSockets;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using BTCPayServer.Data;
|
|
|
|
|
using BTCPayServer.Models.StoreViewModels;
|
|
|
|
|
using BTCPayServer.Payments;
|
|
|
|
|
using BTCPayServer.Services;
|
2018-05-07 05:17:46 +02:00
|
|
|
|
using LedgerWallet;
|
2018-02-25 16:48:12 +01:00
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using NBitcoin;
|
|
|
|
|
using NBXplorer.DerivationStrategy;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
|
|
|
|
namespace BTCPayServer.Controllers
|
|
|
|
|
{
|
|
|
|
|
public partial class StoresController
|
|
|
|
|
{
|
|
|
|
|
[HttpGet]
|
2018-03-20 18:48:11 +01:00
|
|
|
|
[Route("{storeId}/derivations/{cryptoCode}")]
|
2018-04-29 19:33:42 +02:00
|
|
|
|
public IActionResult AddDerivationScheme(string storeId, string cryptoCode)
|
2018-02-25 16:48:12 +01:00
|
|
|
|
{
|
2018-04-29 19:33:42 +02:00
|
|
|
|
var store = HttpContext.GetStoreData();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
if (store == null)
|
|
|
|
|
return NotFound();
|
2018-04-10 12:07:57 +02:00
|
|
|
|
var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode);
|
|
|
|
|
if (network == null)
|
|
|
|
|
{
|
|
|
|
|
return NotFound();
|
|
|
|
|
}
|
2018-03-20 19:05:51 +01:00
|
|
|
|
|
2018-02-25 16:48:12 +01:00
|
|
|
|
DerivationSchemeViewModel vm = new DerivationSchemeViewModel();
|
2018-07-26 15:32:24 +02:00
|
|
|
|
vm.ServerUrl = WalletsController.GetLedgerWebsocketUrl(this.HttpContext, cryptoCode, null);
|
2018-03-20 18:48:11 +01:00
|
|
|
|
vm.CryptoCode = cryptoCode;
|
2018-04-12 04:48:33 +02:00
|
|
|
|
vm.RootKeyPath = network.GetRootKeyPath();
|
2018-03-20 19:05:51 +01:00
|
|
|
|
SetExistingValues(store, vm);
|
2018-02-25 16:48:12 +01:00
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-20 19:05:51 +01:00
|
|
|
|
private void SetExistingValues(StoreData store, DerivationSchemeViewModel vm)
|
|
|
|
|
{
|
|
|
|
|
vm.DerivationScheme = GetExistingDerivationStrategy(vm.CryptoCode, store)?.DerivationStrategyBase.ToString();
|
2018-07-27 13:37:16 +02:00
|
|
|
|
vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike));
|
2018-03-20 19:05:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DerivationStrategy GetExistingDerivationStrategy(string cryptoCode, StoreData store)
|
|
|
|
|
{
|
|
|
|
|
var id = new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike);
|
|
|
|
|
var existing = store.GetSupportedPaymentMethods(_NetworkProvider)
|
|
|
|
|
.OfType<DerivationStrategy>()
|
|
|
|
|
.FirstOrDefault(d => d.PaymentId == id);
|
|
|
|
|
return existing;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-25 16:48:12 +01:00
|
|
|
|
[HttpPost]
|
2018-03-20 18:48:11 +01:00
|
|
|
|
[Route("{storeId}/derivations/{cryptoCode}")]
|
|
|
|
|
public async Task<IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm, string cryptoCode)
|
2018-02-25 16:48:12 +01:00
|
|
|
|
{
|
2018-07-26 15:32:24 +02:00
|
|
|
|
vm.ServerUrl = WalletsController.GetLedgerWebsocketUrl(this.HttpContext, cryptoCode, null);
|
2018-03-20 18:48:11 +01:00
|
|
|
|
vm.CryptoCode = cryptoCode;
|
2018-04-29 19:33:42 +02:00
|
|
|
|
var store = HttpContext.GetStoreData();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
if (store == null)
|
|
|
|
|
return NotFound();
|
|
|
|
|
|
2018-03-20 18:48:11 +01:00
|
|
|
|
var network = cryptoCode == null ? null : _ExplorerProvider.GetNetwork(cryptoCode);
|
2018-02-25 16:48:12 +01:00
|
|
|
|
if (network == null)
|
|
|
|
|
{
|
2018-03-20 18:48:11 +01:00
|
|
|
|
return NotFound();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
}
|
2018-04-12 04:48:33 +02:00
|
|
|
|
vm.RootKeyPath = network.GetRootKeyPath();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
var wallet = _WalletProvider.GetWallet(network);
|
|
|
|
|
if (wallet == null)
|
|
|
|
|
{
|
2018-03-20 18:48:11 +01:00
|
|
|
|
return NotFound();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
2018-08-01 08:59:29 +02:00
|
|
|
|
var exisingStrategy = store.GetSupportedPaymentMethods(_NetworkProvider)
|
|
|
|
|
.Where(c => c.PaymentId == paymentMethodId)
|
|
|
|
|
.OfType<DerivationStrategy>()
|
|
|
|
|
.Select(c => c.DerivationStrategyBase.ToString())
|
|
|
|
|
.FirstOrDefault();
|
2018-02-25 16:48:12 +01:00
|
|
|
|
DerivationStrategy strategy = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(vm.DerivationScheme))
|
|
|
|
|
{
|
2018-03-24 12:40:26 +01:00
|
|
|
|
strategy = ParseDerivationStrategy(vm.DerivationScheme, null, network);
|
2018-02-25 16:48:12 +01:00
|
|
|
|
vm.DerivationScheme = strategy.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme");
|
|
|
|
|
vm.Confirmation = false;
|
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
2018-08-01 08:59:29 +02:00
|
|
|
|
|
|
|
|
|
var showAddress = (vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) || // Testing hint address
|
|
|
|
|
(!vm.Confirmation && strategy != null && exisingStrategy != strategy.DerivationStrategyBase.ToString()); // Checking addresses after setting xpub
|
|
|
|
|
|
|
|
|
|
if (!showAddress)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (strategy != null)
|
|
|
|
|
await wallet.TrackAsync(strategy.DerivationStrategyBase);
|
|
|
|
|
store.SetSupportedPaymentMethod(paymentMethodId, strategy);
|
|
|
|
|
|
|
|
|
|
var storeBlob = store.GetStoreBlob();
|
|
|
|
|
storeBlob.SetExcluded(paymentMethodId, !vm.Enabled);
|
|
|
|
|
store.SetStoreBlob(storeBlob);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme");
|
|
|
|
|
return View(vm);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await _Repo.UpdateStore(store);
|
|
|
|
|
StatusMessage = $"Derivation scheme for {network.CryptoCode} has been modified.";
|
|
|
|
|
return RedirectToAction(nameof(UpdateStore), new { storeId = storeId });
|
|
|
|
|
}
|
|
|
|
|
else if (!string.IsNullOrEmpty(vm.HintAddress))
|
2018-03-24 12:40:26 +01:00
|
|
|
|
{
|
|
|
|
|
BitcoinAddress address = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.HintAddress), "Invalid hint address");
|
|
|
|
|
return ShowAddresses(vm, strategy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
strategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address");
|
|
|
|
|
return ShowAddresses(vm, strategy);
|
|
|
|
|
}
|
|
|
|
|
vm.HintAddress = "";
|
|
|
|
|
vm.StatusMessage = "Address successfully found, please verify that the rest is correct and click on \"Confirm\"";
|
|
|
|
|
ModelState.Remove(nameof(vm.HintAddress));
|
|
|
|
|
ModelState.Remove(nameof(vm.DerivationScheme));
|
2018-02-25 16:48:12 +01:00
|
|
|
|
}
|
2018-08-01 08:59:29 +02:00
|
|
|
|
return ShowAddresses(vm, strategy);
|
2018-03-24 12:40:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IActionResult ShowAddresses(DerivationSchemeViewModel vm, DerivationStrategy strategy)
|
|
|
|
|
{
|
|
|
|
|
vm.DerivationScheme = strategy.DerivationStrategyBase.ToString();
|
|
|
|
|
if (!string.IsNullOrEmpty(vm.DerivationScheme))
|
2018-02-25 16:48:12 +01:00
|
|
|
|
{
|
2018-03-24 12:40:26 +01:00
|
|
|
|
var line = strategy.DerivationStrategyBase.GetLineFor(DerivationFeature.Deposit);
|
2018-02-25 16:48:12 +01:00
|
|
|
|
|
2018-03-24 12:40:26 +01:00
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
|
{
|
|
|
|
|
var address = line.Derive((uint)i);
|
|
|
|
|
vm.AddressSamples.Add((DerivationStrategyBase.GetKeyPath(DerivationFeature.Deposit).Derive((uint)i).ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString()));
|
2018-02-25 16:48:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-24 12:40:26 +01:00
|
|
|
|
vm.Confirmation = true;
|
|
|
|
|
return View(vm);
|
2018-02-25 16:48:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|