Commit bbec71c8 authored by Jeremy Bokobza's avatar Jeremy Bokobza

Removed the WalletWrapper as we don't have Hbitcoin anymore

parent e6f7cf8f
...@@ -8,6 +8,7 @@ using Breeze.Wallet.Errors; ...@@ -8,6 +8,7 @@ using Breeze.Wallet.Errors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Breeze.Wallet.Models; using Breeze.Wallet.Models;
using Breeze.Wallet.Wrappers; using Breeze.Wallet.Wrappers;
using NBitcoin;
namespace Breeze.Wallet.Controllers namespace Breeze.Wallet.Controllers
{ {
...@@ -17,42 +18,42 @@ namespace Breeze.Wallet.Controllers ...@@ -17,42 +18,42 @@ namespace Breeze.Wallet.Controllers
[Route("api/v{version:apiVersion}/[controller]")] [Route("api/v{version:apiVersion}/[controller]")]
public class WalletController : Controller public class WalletController : Controller
{ {
private readonly IWalletWrapper walletWrapper; private readonly IWalletManager walletManager;
public WalletController(IWalletWrapper walletWrapper) public WalletController(IWalletManager walletManager)
{ {
this.walletWrapper = walletWrapper; this.walletManager = walletManager;
} }
/// <summary> /// <summary>
/// Creates a new wallet on the local machine. /// Creates a new wallet on the local machine.
/// </summary> /// </summary>
/// <param name="request">The object containing the parameters used to create the wallet.</param> /// <param name="request">The object containing the parameters used to create the wallet.</param>
/// <returns>A JSON object containing the mnemonic created for the new wallet.</returns> /// <returns>A JSON object containing the mnemonic created for the new wallet.</returns>
[Route("create")] [Route("create")]
[HttpPost] [HttpPost]
public IActionResult Create([FromBody]WalletCreationRequest request) public IActionResult Create([FromBody]WalletCreationRequest request)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
// get the wallet folder // get the wallet folder
DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath); DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath);
Mnemonic mnemonic = this.walletManager.CreateWallet(request.Password, walletFolder.FullName, request.Name, request.Network);
var mnemonic = this.walletWrapper.Create(request.Password, walletFolder.FullName, request.Name, request.Network); return this.Json(mnemonic.ToString());
return this.Json(mnemonic);
} }
catch (InvalidOperationException e) catch (InvalidOperationException e)
{ {
// indicates that this wallet already exists // indicates that this wallet already exists
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Conflict, "This wallet already exists.", e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Conflict, "This wallet already exists.", e.ToString());
} }
} }
/// <summary> /// <summary>
...@@ -61,38 +62,42 @@ namespace Breeze.Wallet.Controllers ...@@ -61,38 +62,42 @@ namespace Breeze.Wallet.Controllers
/// <param name="request">The name of the wallet to load.</param> /// <param name="request">The name of the wallet to load.</param>
/// <returns></returns> /// <returns></returns>
[Route("load")] [Route("load")]
[HttpPost] [HttpPost]
public IActionResult Load([FromBody]WalletLoadRequest request) public IActionResult Load([FromBody]WalletLoadRequest request)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
// get the wallet folder // get the wallet folder
DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath); DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath);
var wallet = this.walletWrapper.Load(request.Password, walletFolder.FullName, request.Name); Wallet wallet = this.walletManager.LoadWallet(request.Password, walletFolder.FullName, request.Name);
return this.Json(wallet); return this.Json(new WalletModel
{
} Network = wallet.Network.Name,
// Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = wallet.WalletFilePath
});
}
catch (FileNotFoundException e) catch (FileNotFoundException e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.NotFound, "This wallet was not found at the specified location.", e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.NotFound, "This wallet was not found at the specified location.", e.ToString());
} }
catch (SecurityException e) catch (SecurityException e)
{ {
// indicates that the password is wrong // indicates that the password is wrong
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Wrong password, please try again.", e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Wrong password, please try again.", e.ToString());
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
...@@ -108,16 +113,21 @@ namespace Breeze.Wallet.Controllers ...@@ -108,16 +113,21 @@ namespace Breeze.Wallet.Controllers
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
// get the wallet folder // get the wallet folder
DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath); DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath);
var wallet = this.walletWrapper.Recover(request.Password, walletFolder.FullName, request.Name, request.Network, request.Mnemonic); Wallet wallet = this.walletManager.RecoverWallet(request.Password, walletFolder.FullName, request.Name, request.Network, request.Mnemonic);
return this.Json(wallet); return this.Json(new WalletModel
{
Network = wallet.Network.Name,
// Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = wallet.WalletFilePath
});
} }
catch (InvalidOperationException e) catch (InvalidOperationException e)
{ {
...@@ -126,41 +136,41 @@ namespace Breeze.Wallet.Controllers ...@@ -126,41 +136,41 @@ namespace Breeze.Wallet.Controllers
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
{ {
// indicates that this wallet does not exist // indicates that this wallet does not exist
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.NotFound, "Wallet not found.", e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.NotFound, "Wallet not found.", e.ToString());
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Get some general info about a wallet. /// Get some general info about a wallet.
/// </summary> /// </summary>
/// <param name="model">The name of the wallet.</param> /// <param name="model">The name of the wallet.</param>
/// <returns></returns> /// <returns></returns>
[Route("general-info")] [Route("general-info")]
[HttpGet] [HttpGet]
public IActionResult GetGeneralInfo([FromQuery] WalletName model) public IActionResult GetGeneralInfo([FromQuery] WalletName model)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
return this.Json(this.walletWrapper.GetGeneralInfo(model.Name)); return this.Json(this.walletManager.GetGeneralInfo(model.Name));
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Retrieves the history of a wallet. /// Retrieves the history of a wallet.
...@@ -168,26 +178,26 @@ namespace Breeze.Wallet.Controllers ...@@ -168,26 +178,26 @@ namespace Breeze.Wallet.Controllers
/// <param name="model">The name of the wallet.</param> /// <param name="model">The name of the wallet.</param>
/// <returns></returns> /// <returns></returns>
[Route("history")] [Route("history")]
[HttpGet] [HttpGet]
public IActionResult GetHistory([FromQuery] WalletName model) public IActionResult GetHistory([FromQuery] WalletName model)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
return this.Json(this.walletWrapper.GetHistory(model.Name)); return this.Json(this.walletManager.GetHistory(model.Name));
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Gets the balance of a wallet. /// Gets the balance of a wallet.
...@@ -195,26 +205,26 @@ namespace Breeze.Wallet.Controllers ...@@ -195,26 +205,26 @@ namespace Breeze.Wallet.Controllers
/// <param name="model">The name of the wallet.</param> /// <param name="model">The name of the wallet.</param>
/// <returns></returns> /// <returns></returns>
[Route("balance")] [Route("balance")]
[HttpGet] [HttpGet]
public IActionResult GetBalance([FromQuery] WalletName model) public IActionResult GetBalance([FromQuery] WalletName model)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
return this.Json(this.walletWrapper.GetBalance(model.Name)); return this.Json(this.walletManager.GetBalance(model.Name));
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Builds a transaction. /// Builds a transaction.
...@@ -222,26 +232,26 @@ namespace Breeze.Wallet.Controllers ...@@ -222,26 +232,26 @@ namespace Breeze.Wallet.Controllers
/// <param name="request">The transaction parameters.</param> /// <param name="request">The transaction parameters.</param>
/// <returns>All the details of the transaction, including the hex used to execute it.</returns> /// <returns>All the details of the transaction, including the hex used to execute it.</returns>
[Route("build-transaction")] [Route("build-transaction")]
[HttpPost] [HttpPost]
public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request) public IActionResult BuildTransaction([FromBody] BuildTransactionRequest request)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
return this.Json(this.walletWrapper.BuildTransaction(request.Password, request.Address, request.Amount, request.FeeType, request.AllowUnconfirmed)); return this.Json(this.walletManager.BuildTransaction(request.Password, request.Address, request.Amount, request.FeeType, request.AllowUnconfirmed));
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Sends a transaction. /// Sends a transaction.
...@@ -249,31 +259,31 @@ namespace Breeze.Wallet.Controllers ...@@ -249,31 +259,31 @@ namespace Breeze.Wallet.Controllers
/// <param name="request">The hex representing the transaction.</param> /// <param name="request">The hex representing the transaction.</param>
/// <returns></returns> /// <returns></returns>
[Route("send-transaction")] [Route("send-transaction")]
[HttpPost] [HttpPost]
public IActionResult SendTransaction([FromBody] SendTransactionRequest request) public IActionResult SendTransaction([FromBody] SendTransactionRequest request)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
{ {
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage)); var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors)); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
} }
try try
{ {
var result = this.walletWrapper.SendTransaction(request.Hex); var result = this.walletManager.SendTransaction(request.Hex);
if (result) if (result)
{ {
return this.Ok(); return this.Ok();
} }
return this.StatusCode((int)HttpStatusCode.BadRequest); return this.StatusCode((int)HttpStatusCode.BadRequest);
} }
catch (Exception e) catch (Exception e)
{ {
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString()); return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
} }
} }
/// <summary> /// <summary>
/// Lists all the wallet files found under the default folder. /// Lists all the wallet files found under the default folder.
...@@ -282,7 +292,7 @@ namespace Breeze.Wallet.Controllers ...@@ -282,7 +292,7 @@ namespace Breeze.Wallet.Controllers
[Route("files")] [Route("files")]
[HttpGet] [HttpGet]
public IActionResult ListWalletsFiles() public IActionResult ListWalletsFiles()
{ {
try try
{ {
DirectoryInfo walletsFolder = GetWalletFolder(); DirectoryInfo walletsFolder = GetWalletFolder();
...@@ -307,7 +317,7 @@ namespace Breeze.Wallet.Controllers ...@@ -307,7 +317,7 @@ namespace Breeze.Wallet.Controllers
/// <returns>The path folder of the folder.</returns> /// <returns>The path folder of the folder.</returns>
/// <remarks>The folder is created if it doesn't exist.</remarks> /// <remarks>The folder is created if it doesn't exist.</remarks>
private static DirectoryInfo GetWalletFolder(string folderPath = null) private static DirectoryInfo GetWalletFolder(string folderPath = null)
{ {
if (string.IsNullOrEmpty(folderPath)) if (string.IsNullOrEmpty(folderPath))
{ {
folderPath = GetDefaultWalletFolderPath(); folderPath = GetDefaultWalletFolderPath();
...@@ -320,12 +330,12 @@ namespace Breeze.Wallet.Controllers ...@@ -320,12 +330,12 @@ namespace Breeze.Wallet.Controllers
/// </summary> /// </summary>
/// <returns>The folder path for Windows, Linux or OSX systems.</returns> /// <returns>The folder path for Windows, Linux or OSX systems.</returns>
private static string GetDefaultWalletFolderPath() private static string GetDefaultWalletFolderPath()
{ {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
return $@"{Environment.GetEnvironmentVariable("AppData")}\Breeze"; return $@"{Environment.GetEnvironmentVariable("AppData")}\Breeze";
} }
return $"{Environment.GetEnvironmentVariable("HOME")}/.breeze"; return $"{Environment.GetEnvironmentVariable("HOME")}/.breeze";
} }
} }
......
using System; using System;
using Breeze.Wallet.Models;
using NBitcoin; using NBitcoin;
namespace Breeze.Wallet namespace Breeze.Wallet
...@@ -12,36 +13,49 @@ namespace Breeze.Wallet ...@@ -12,36 +13,49 @@ namespace Breeze.Wallet
/// Creates a wallet and persist it as a file on the local system. /// Creates a wallet and persist it as a file on the local system.
/// </summary> /// </summary>
/// <param name="password">The password used to encrypt sensitive info.</param> /// <param name="password">The password used to encrypt sensitive info.</param>
/// <param name="passphrase">The passphrase used in the seed.</param> /// <param name="folderPath">The folder where the wallet will be saved.</param>
/// <param name="walletFilePath">The path where the wallet file will be created.</param> /// <param name="name">The name of the wallet.</param>
/// <param name="network">The network this wallet is for.</param> /// <param name="network">The network this wallet is for.</param>
/// <param name="passphrase">The passphrase used in the seed.</param>
/// <returns>A mnemonic defining the wallet's seed used to generate addresses.</returns> /// <returns>A mnemonic defining the wallet's seed used to generate addresses.</returns>
Mnemonic CreateWallet(string password, string walletFilePath, Network network, string passphrase = null); Mnemonic CreateWallet(string password, string folderPath, string name, string network, string passphrase = null);
/// <summary> /// <summary>
/// Loads a wallet from a file. /// Loads a wallet from a file.
/// </summary> /// </summary>
/// <param name="password">The password used to encrypt sensitive info.</param> /// <param name="password">The user's password.</param>
/// <param name="walletFilePath">The location of the wallet file.</param> /// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the wallet.</param>
/// <returns>The wallet.</returns> /// <returns>The wallet.</returns>
Wallet LoadWallet(string password, string walletFilePath); Wallet LoadWallet(string password, string folderPath, string name);
/// <summary> /// <summary>
/// Recovers a wallet. /// Recovers a wallet.
/// </summary> /// </summary>
/// <param name="mnemonic">A mnemonic defining the wallet's seed used to generate addresses.</param> /// <param name="password">The user's password.</param>
/// <param name="password">The password used to encrypt sensitive info.</param> /// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="walletFilePath">The location of the wallet file.</param> /// <param name="name">The name of the wallet.</param>
/// <param name="network">The network this wallet is for.</param> /// <param name="network">The network in which to creae this wallet</param>
/// <param name="mnemonic">The user's mnemonic for the wallet.</param>
/// <param name="passphrase">The passphrase used in the seed.</param> /// <param name="passphrase">The passphrase used in the seed.</param>
/// <param name="creationTime">The time this wallet was created.</param> /// <param name="creationTime">The time this wallet was created.</param>
/// <returns>The recovered wallet.</returns> /// <returns>The recovered wallet.</returns>
Wallet RecoverWallet(Mnemonic mnemonic, string password, string walletFilePath, Network network, string passphrase = null, DateTimeOffset? creationTime = null); Wallet RecoverWallet(string password, string folderPath, string name, string network, string mnemonic, string passphrase = null, DateTimeOffset? creationTime = null);
/// <summary> /// <summary>
/// Deleted a wallet. /// Deleted a wallet.
/// </summary> /// </summary>
/// <param name="walletFilePath">The location of the wallet file.</param> /// <param name="walletFilePath">The location of the wallet file.</param>
void DeleteWallet(string walletFilePath); void DeleteWallet(string walletFilePath);
WalletGeneralInfoModel GetGeneralInfo(string walletName);
WalletBalanceModel GetBalance(string walletName);
WalletHistoryModel GetHistory(string walletName);
WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType, bool allowUnconfirmed);
bool SendTransaction(string transactionHex);
} }
} }
...@@ -9,46 +9,45 @@ using Stratis.Bitcoin.Builder; ...@@ -9,46 +9,45 @@ using Stratis.Bitcoin.Builder;
namespace Breeze.Wallet namespace Breeze.Wallet
{ {
public class WalletFeature : FullNodeFeature public class WalletFeature : FullNodeFeature
{ {
private readonly ITrackerWrapper trackerWrapper; private readonly ITrackerWrapper trackerWrapper;
private readonly Signals signals; private readonly Signals signals;
private readonly ConcurrentChain chain; private readonly ConcurrentChain chain;
public WalletFeature(ITrackerWrapper trackerWrapper, Signals signals, ConcurrentChain chain) public WalletFeature(ITrackerWrapper trackerWrapper, Signals signals, ConcurrentChain chain)
{ {
this.trackerWrapper = trackerWrapper; this.trackerWrapper = trackerWrapper;
this.signals = signals; this.signals = signals;
this.chain = chain; this.chain = chain;
} }
public override void Start() public override void Start()
{ {
BlockSubscriber sub = new BlockSubscriber(signals.Blocks, new BlockObserver(chain, trackerWrapper)); BlockSubscriber sub = new BlockSubscriber(signals.Blocks, new BlockObserver(chain, trackerWrapper));
sub.Subscribe(); sub.Subscribe();
TransactionSubscriber txSub = new TransactionSubscriber(signals.Transactions, new TransactionObserver(trackerWrapper)); TransactionSubscriber txSub = new TransactionSubscriber(signals.Transactions, new TransactionObserver(trackerWrapper));
txSub.Subscribe(); txSub.Subscribe();
} }
} }
public static class WalletFeatureExtension public static class WalletFeatureExtension
{ {
public static IFullNodeBuilder UseWallet(this IFullNodeBuilder fullNodeBuilder) public static IFullNodeBuilder UseWallet(this IFullNodeBuilder fullNodeBuilder)
{ {
fullNodeBuilder.ConfigureFeature(features => fullNodeBuilder.ConfigureFeature(features =>
{ {
features features
.AddFeature<WalletFeature>() .AddFeature<WalletFeature>()
.FeatureServices(services => .FeatureServices(services =>
{ {
services.AddTransient<IWalletWrapper, WalletWrapper>(); services.AddSingleton<ITrackerWrapper, TrackerWrapper>();
services.AddSingleton<ITrackerWrapper, TrackerWrapper>(); services.AddSingleton<IWalletManager, WalletManager>();
services.AddSingleton<IWalletManager, WalletManager>(); services.AddSingleton<WalletController>();
services.AddSingleton<WalletController>(); });
}); });
});
return fullNodeBuilder; return fullNodeBuilder;
} }
} }
} }
using System; using System;
using System.IO; using System.IO;
using Breeze.Wallet.Helpers;
using Breeze.Wallet.Models;
using NBitcoin; using NBitcoin;
using Newtonsoft.Json; using Newtonsoft.Json;
...@@ -9,48 +11,90 @@ namespace Breeze.Wallet ...@@ -9,48 +11,90 @@ namespace Breeze.Wallet
/// A manager providing operations on wallets. /// A manager providing operations on wallets.
/// </summary> /// </summary>
public class WalletManager : IWalletManager public class WalletManager : IWalletManager
{ {
/// <inheritdoc /> /// <inheritdoc />
public Mnemonic CreateWallet(string password, string walletFilePath, Network network, string passphrase = null) public Mnemonic CreateWallet(string password, string folderPath, string name, string network, string passphrase = null)
{ {
string walletFilePath = Path.Combine(folderPath, $"{name}.json");
// for now the passphrase is set to be the password by default.
if (passphrase == null)
{
passphrase = password;
}
// generate the root seed used to generate keys from a mnemonic picked at random // generate the root seed used to generate keys from a mnemonic picked at random
// and a passphrase optionally provided by the user // and a passphrase optionally provided by the user
Mnemonic mnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve); Mnemonic mnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve);
ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase); ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase);
// create a wallet file // create a wallet file
Wallet wallet = this.GenerateWalletFile(password, walletFilePath, network, extendedKey); Wallet wallet = this.GenerateWalletFile(password, walletFilePath, WalletHelpers.GetNetwork(network), extendedKey);
return mnemonic; return mnemonic;
} }
/// <inheritdoc /> /// <inheritdoc />
public Wallet LoadWallet(string password, string walletFilePath) public Wallet LoadWallet(string password, string folderPath, string name)
{ {
string walletFilePath = Path.Combine(folderPath, $"{name}.json");
if (!File.Exists(walletFilePath)) if (!File.Exists(walletFilePath))
throw new FileNotFoundException($"No wallet file found at {walletFilePath}"); throw new FileNotFoundException($"No wallet file found at {walletFilePath}");
// load the file from the local system // load the file from the local system
Wallet wallet = JsonConvert.DeserializeObject<Wallet>(File.ReadAllText(walletFilePath)); Wallet wallet = JsonConvert.DeserializeObject<Wallet>(File.ReadAllText(walletFilePath));
return wallet; return wallet;
} }
/// <inheritdoc /> /// <inheritdoc />
public Wallet RecoverWallet(Mnemonic mnemonic, string password, string walletFilePath, Network network, string passphrase = null, DateTimeOffset? creationTime = null) public Wallet RecoverWallet(string password, string folderPath, string name, string network, string mnemonic, string passphrase = null, DateTimeOffset? creationTime = null)
{ {
// for now the passphrase is set to be the password by default.
if (passphrase == null)
{
passphrase = password;
}
// generate the root seed used to generate keys // generate the root seed used to generate keys
ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase); ExtKey extendedKey = (new Mnemonic(mnemonic)).DeriveExtKey(passphrase);
// create a wallet file // create a wallet file
Wallet wallet = this.GenerateWalletFile(password, walletFilePath, network, extendedKey, creationTime); Wallet wallet = this.GenerateWalletFile(password, Path.Combine(folderPath, $"{name}.json"), WalletHelpers.GetNetwork(network), extendedKey, creationTime);
return wallet; return wallet;
} }
public WalletGeneralInfoModel GetGeneralInfo(string name)
{
throw new System.NotImplementedException();
}
public WalletBalanceModel GetBalance(string walletName)
{
throw new System.NotImplementedException();
}
public WalletHistoryModel GetHistory(string walletName)
{
throw new System.NotImplementedException();
}
public WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType,
bool allowUnconfirmed)
{
throw new System.NotImplementedException();
}
public bool SendTransaction(string transactionHex)
{
throw new System.NotImplementedException();
}
/// <inheritdoc /> /// <inheritdoc />
public void DeleteWallet(string walletFilePath) public void DeleteWallet(string walletFilePath)
{ {
File.Delete(walletFilePath); File.Delete(walletFilePath);
} }
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() public void Dispose()
{ {
...@@ -77,7 +121,7 @@ namespace Breeze.Wallet ...@@ -77,7 +121,7 @@ namespace Breeze.Wallet
EncryptedSeed = extendedKey.PrivateKey.GetEncryptedBitcoinSecret(password, network).ToWif(), EncryptedSeed = extendedKey.PrivateKey.GetEncryptedBitcoinSecret(password, network).ToWif(),
ChainCode = extendedKey.ChainCode, ChainCode = extendedKey.ChainCode,
CreationTime = creationTime ?? DateTimeOffset.Now, CreationTime = creationTime ?? DateTimeOffset.Now,
Network = network Network = network
}; };
// create a folder if none exists and persist the file // create a folder if none exists and persist the file
......
using Breeze.Wallet.Models;
using NBitcoin;
namespace Breeze.Wallet.Wrappers
{
/// <summary>
/// An interface enabling wallet operations.
/// </summary>
public interface IWalletWrapper
{
string Create(string password, string folderPath, string name, string network);
WalletModel Load(string password, string folderPath, string name);
WalletModel Recover(string password, string folderPath, string name, string network, string mnemonic);
WalletGeneralInfoModel GetGeneralInfo(string walletName);
WalletBalanceModel GetBalance(string walletName);
WalletHistoryModel GetHistory(string walletName);
WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType, bool allowUnconfirmed);
bool SendTransaction(string transactionHex);
}
}
using System;
using System.IO;
using System.Linq;
using Breeze.Wallet.Helpers;
using Breeze.Wallet.Models;
using NBitcoin;
namespace Breeze.Wallet.Wrappers
{
/// <summary>
/// An implementation of the <see cref="IWalletWrapper"/> interface.
/// </summary>
public class WalletWrapper : IWalletWrapper
{
private readonly IWalletManager walletManager;
public WalletWrapper(IWalletManager walletManager)
{
this.walletManager = walletManager;
}
/// <summary>
/// Creates a wallet on the local device.
/// </summary>
/// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the wallet will be saved.</param>
/// <param name="name">The name of the wallet.</param>
/// <param name="network">The network for which to create a wallet.</param>
/// <returns>A mnemonic allowing recovery of the wallet.</returns>
public string Create(string password, string folderPath, string name, string network)
{
Mnemonic mnemonic = this.walletManager.CreateWallet(password, Path.Combine(folderPath, $"{name}.json"), WalletHelpers.GetNetwork(network), password);
return mnemonic.ToString();
}
/// <summary>
/// Loads a wallet from the local device.
/// </summary>
/// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the wallet.</param>
/// <returns>The wallet loaded from the local device</returns>
public WalletModel Load(string password, string folderPath, string name)
{
Wallet wallet = this.walletManager.LoadWallet(password, Path.Combine(folderPath, $"{name}.json"));
//TODO review here which data should be returned
return new WalletModel
{
Network = wallet.Network.Name,
// Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = wallet.WalletFilePath
};
}
/// <summary>
/// Recovers a wallet from the local device.
/// </summary>
/// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the wallet.</param>
/// <param name="network">The network in which to creae this wallet</param>
/// <param name="mnemonic">The user's mnemonic for the wallet.</param>
/// <returns></returns>
public WalletModel Recover(string password, string folderPath, string name, string network, string mnemonic)
{
Wallet wallet = this.walletManager.RecoverWallet(new Mnemonic(mnemonic), password, Path.Combine(folderPath, $"{name}.json"), WalletHelpers.GetNetwork(network), password);
//TODO review here which data should be returned
return new WalletModel
{
Network = wallet.Network.Name,
// Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = wallet.WalletFilePath
};
}
public WalletGeneralInfoModel GetGeneralInfo(string name)
{
throw new System.NotImplementedException();
}
public WalletBalanceModel GetBalance(string walletName)
{
throw new System.NotImplementedException();
}
public WalletHistoryModel GetHistory(string walletName)
{
throw new System.NotImplementedException();
}
public WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType,
bool allowUnconfirmed)
{
throw new System.NotImplementedException();
}
public bool SendTransaction(string transactionHex)
{
throw new System.NotImplementedException();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment