Commit e6f7cf8f authored by Jeremy Bokobza's avatar Jeremy Bokobza

Merged the Wallet and WalletFIle objects, no need to have both.

Added a WalletHierarchy class to contain accounts, addresses and transactions.
parent 73763b96
using System; using System;
using Breeze.Wallet.JsonConverters;
using NBitcoin; using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet namespace Breeze.Wallet
{ {
...@@ -8,29 +10,44 @@ namespace Breeze.Wallet ...@@ -8,29 +10,44 @@ namespace Breeze.Wallet
/// </summary> /// </summary>
public class Wallet public class Wallet
{ {
/// <summary>
/// The seed for this wallet, password encrypted.
/// </summary>
[JsonProperty(PropertyName = "encryptedSeed")]
public string EncryptedSeed { get; set; }
/// <summary> /// <summary>
/// The chain code. /// The chain code.
/// </summary> /// </summary>
[JsonProperty(PropertyName = "chainCode")]
[JsonConverter(typeof(ByteArrayConverter))]
public byte[] ChainCode { get; set; } public byte[] ChainCode { get; set; }
/// <summary> /// <summary>
/// The network this wallet is for. /// The network this wallet is for.
/// </summary> /// </summary>
[JsonProperty(PropertyName = "network")]
[JsonConverter(typeof(NetworkConverter))]
public Network Network { get; set; } public Network Network { get; set; }
/// <summary> /// <summary>
/// The time this wallet was created. /// The time this wallet was created.
/// </summary> /// </summary>
[JsonProperty(PropertyName = "creationTime")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset CreationTime { get; set; } public DateTimeOffset CreationTime { get; set; }
/// <summary> /// <summary>
/// The location of the wallet file on the local system. /// The location of the wallet file on the local system.
/// </summary> /// </summary>
[JsonIgnore]
public string WalletFilePath { get; set; } public string WalletFilePath { get; set; }
/// <summary> /// <summary>
/// The key used to generate keys. /// The hierarchy of the wallet's accounts and addresses.
/// </summary> /// </summary>
public ExtKey ExtendedKey { get; set; } [JsonProperty(PropertyName = "hierarchy")]
public WalletHierarchy Hierarchy { get; set; }
} }
} }
\ No newline at end of file
...@@ -42,9 +42,9 @@ namespace Breeze.Wallet ...@@ -42,9 +42,9 @@ namespace Breeze.Wallet
.FeatureServices(services => .FeatureServices(services =>
{ {
services.AddTransient<IWalletWrapper, WalletWrapper>(); services.AddTransient<IWalletWrapper, WalletWrapper>();
services.AddTransient<ITrackerWrapper, TrackerWrapper>(); services.AddSingleton<ITrackerWrapper, TrackerWrapper>();
services.AddSingleton<IWalletManager, WalletManager>(); services.AddSingleton<IWalletManager, WalletManager>();
services.AddSingleton<WalletController>(); services.AddSingleton<WalletController>();
}); });
}); });
......
using System;
using NBitcoin;
using Newtonsoft.Json;
using Breeze.Wallet.JsonConverters;
namespace Breeze.Wallet
{
/// <summary>
/// An object representing a wallet on a local file system.
/// </summary>
public class WalletFile
{
/// <summary>
/// The seed for this wallet, password encrypted.
/// </summary>
[JsonProperty(PropertyName = "encryptedSeed")]
public string EncryptedSeed { get; set; }
/// <summary>
/// The chain code.
/// </summary>
[JsonProperty(PropertyName = "chainCode")]
[JsonConverter(typeof(ByteArrayConverter))]
public byte[] ChainCode { get; set; }
/// <summary>
/// The network this wallet is for.
/// </summary>
[JsonProperty(PropertyName = "network")]
[JsonConverter(typeof(NetworkConverter))]
public Network Network { get; set; }
/// <summary>
/// The time this wallet was created.
/// </summary>
[JsonProperty(PropertyName = "creationTime")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset CreationTime { get; set; }
}
}
using System;
using System.Collections.Generic;
using Breeze.Wallet.JsonConverters;
using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet
{
/// <summary>
/// Represents the root of the user's wallet's addresses and transactions.
/// </summary>
public class WalletHierarchy
{
/// <summary>
/// The type of coin, Bitcoin or Stratis.
/// </summary>
[JsonProperty(PropertyName = "coinType")]
public CoinType CoinType { get; set; }
/// <summary>
/// The accounts used in the wallet.
/// </summary>
[JsonProperty(PropertyName = "accounts")]
public IEnumerable<HdAccount> Accounts { get; set; }
}
/// <summary>
/// The type of coin, as specified in BIP44.
/// </summary>
public enum CoinType
{
Bitcoin = 0,
Stratis = 105
}
/// <summary>
/// An Hd account's details.
/// </summary>
public class HdAccount
{
/// <summary>
/// The index of the account.
/// </summary>
/// <remarks>
/// According to BIP44, an account at index (i) can only be created when the account
/// at index (i - 1) contains transactions.
/// </remarks>
[JsonProperty(PropertyName = "index")]
public int Index { get; set; }
/// <summary>
/// The list of external addresses, typically used for receiving money.
/// </summary>
[JsonProperty(PropertyName = "externalAddresses")]
public IEnumerable<HdAddress> ExternalAddresses { get; set; }
/// <summary>
/// The list of internal addresses, typically used to receive change.
/// </summary>
[JsonProperty(PropertyName = "internalAddresses")]
public IEnumerable<HdAddress> InternalAddresses { get; set; }
}
/// <summary>
/// An Hd address.
/// </summary>
public class HdAddress
{
/// <summary>
/// Gets or sets the creation time.
/// </summary>
[JsonProperty(PropertyName = "creationTime")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset CreationTime { get; set; }
/// <summary>
/// The script pub key for this address.
/// </summary>
[JsonProperty(PropertyName = "scriptPubKey")]
public Script ScriptPubKey { get; set; }
/// <summary>
/// The Base58 representation of this address.
/// </summary>
[JsonProperty(PropertyName = "address")]
public BitcoinAddress Address { get; set; }
/// <summary>
/// A path to the address as defined in BIP44.
/// </summary>
[JsonProperty(PropertyName = "hdPath")]
public string HdPath { get; set; }
/// <summary>
/// A list detailing which blocks have been scanned for this address.
/// </summary>
[JsonIgnore]
public SortedList<int, int> BlocksScanned { get; set; }
/// <summary>
/// A list of transactions involving this address.
/// </summary>
[JsonProperty(PropertyName = "transactions")]
public IEnumerable<TransactionData> Transactions { get; set; }
}
/// <summary>
/// An object containing transaction data.
/// </summary>
public class TransactionData
{
/// <summary>
/// Transaction id.
/// </summary>
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
/// <summary>
/// The transaction amount.
/// </summary>
[JsonProperty(PropertyName = "amount")]
public Money Amount { get; set; }
/// <summary>
/// The height of the block including this transaction.
/// </summary>
[JsonProperty(PropertyName = "blockHeight")]
public int BlockHeight { get; set; }
/// <summary>
/// Whether this transaction has been confirmed or not.
/// </summary>
[JsonProperty(PropertyName = "confirmed")]
public bool Confirmed { get; set; }
/// <summary>
/// Gets or sets the creation time.
/// </summary>
[JsonProperty(PropertyName = "creationTime")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset CreationTime { get; set; }
}
}
...@@ -19,8 +19,7 @@ namespace Breeze.Wallet ...@@ -19,8 +19,7 @@ namespace Breeze.Wallet
ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase); ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase);
// create a wallet file // create a wallet file
this.GenerateWalletFile(password, walletFilePath, network, extendedKey); Wallet wallet = this.GenerateWalletFile(password, walletFilePath, network, extendedKey);
return mnemonic; return mnemonic;
} }
...@@ -31,21 +30,7 @@ namespace Breeze.Wallet ...@@ -31,21 +30,7 @@ namespace Breeze.Wallet
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
WalletFile walletFile = JsonConvert.DeserializeObject<WalletFile>(File.ReadAllText(walletFilePath)); Wallet wallet = JsonConvert.DeserializeObject<Wallet>(File.ReadAllText(walletFilePath));
// decrypt the private key and use it to regenerate the seed
var privateKey = Key.Parse(walletFile.EncryptedSeed, password, walletFile.Network);
var seedExtKey = new ExtKey(privateKey, walletFile.ChainCode);
Wallet wallet = new Wallet
{
ChainCode = walletFile.ChainCode,
CreationTime = walletFile.CreationTime,
Network = walletFile.Network,
WalletFilePath = walletFilePath,
ExtendedKey = seedExtKey
};
return wallet; return wallet;
} }
...@@ -56,17 +41,7 @@ namespace Breeze.Wallet ...@@ -56,17 +41,7 @@ namespace Breeze.Wallet
ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase); ExtKey extendedKey = mnemonic.DeriveExtKey(passphrase);
// create a wallet file // create a wallet file
WalletFile walletFile = this.GenerateWalletFile(password, walletFilePath, network, extendedKey, creationTime); Wallet wallet = this.GenerateWalletFile(password, walletFilePath, network, extendedKey, creationTime);
Wallet wallet = new Wallet
{
ChainCode = walletFile.ChainCode,
CreationTime = walletFile.CreationTime,
Network = walletFile.Network,
WalletFilePath = walletFilePath,
ExtendedKey = extendedKey
};
return wallet; return wallet;
} }
...@@ -92,17 +67,17 @@ namespace Breeze.Wallet ...@@ -92,17 +67,17 @@ namespace Breeze.Wallet
/// <param name="creationTime">The time this wallet was created.</param> /// <param name="creationTime">The time this wallet was created.</param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="System.NotSupportedException"></exception> /// <exception cref="System.NotSupportedException"></exception>
private WalletFile GenerateWalletFile(string password, string walletFilePath, Network network, ExtKey extendedKey, DateTimeOffset? creationTime = null) private Wallet GenerateWalletFile(string password, string walletFilePath, Network network, ExtKey extendedKey, DateTimeOffset? creationTime = null)
{ {
if (File.Exists(walletFilePath)) if (File.Exists(walletFilePath))
throw new InvalidOperationException($"Wallet already exists at {walletFilePath}"); throw new InvalidOperationException($"Wallet already exists at {walletFilePath}");
WalletFile walletFile = new WalletFile Wallet walletFile = new 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
......
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