Commit 1dc3c9a7 authored by Pieterjan Vanhoof's avatar Pieterjan Vanhoof Committed by GitHub

Merge pull request #38 from bokobza/feature/history

Added getting the balance for the user's accounts
parents e4036778 bae6052a
This diff is collapsed.
...@@ -110,7 +110,7 @@ ...@@ -110,7 +110,7 @@
{ {
"name": "Get Wallet History", "name": "Get Wallet History",
"request": { "request": {
"url": "http://localhost:5000/api/v1/wallet/history?name=mywallet", "url": "http://localhost:5000/api/v1/wallet/history?walletname=wallet1&cointype=0",
"method": "GET", "method": "GET",
"header": [ "header": [
{ {
...@@ -130,7 +130,7 @@ ...@@ -130,7 +130,7 @@
{ {
"name": "Get wallet balance", "name": "Get wallet balance",
"request": { "request": {
"url": "http://localhost:5000/api/v1/wallet/balance?name=mywallet", "url": "http://localhost:5000/api/v1/wallet/balance?walletname=wallet1&cointype=0",
"method": "GET", "method": "GET",
"header": [ "header": [
{ {
......
...@@ -121,7 +121,7 @@ namespace Breeze.Wallet.Controllers ...@@ -121,7 +121,7 @@ namespace Breeze.Wallet.Controllers
DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath); DirectoryInfo walletFolder = GetWalletFolder(request.FolderPath);
Wallet wallet = this.walletManager.RecoverWallet(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);
// TODO give the tracker the date at which this wallet was originally created so that it can start syncing blocks for it // TODO give the tracker the date at which this wallet was originally created so that it can start syncing blocks for it
return this.Json(new WalletModel return this.Json(new WalletModel
...@@ -192,7 +192,7 @@ namespace Breeze.Wallet.Controllers ...@@ -192,7 +192,7 @@ namespace Breeze.Wallet.Controllers
try try
{ {
WalletHistoryModel model = new WalletHistoryModel {Transactions = new List<TransactionItem>()}; WalletHistoryModel model = new WalletHistoryModel { Transactions = new List<TransactionItem>() };
var accounts = this.walletManager.GetAccountsByCoinType(request.WalletName, request.CoinType).ToList(); var accounts = this.walletManager.GetAccountsByCoinType(request.WalletName, request.CoinType).ToList();
foreach (var address in accounts.SelectMany(a => a.ExternalAddresses).Concat(accounts.SelectMany(a => a.InternalAddresses))) foreach (var address in accounts.SelectMany(a => a.ExternalAddresses).Concat(accounts.SelectMany(a => a.InternalAddresses)))
...@@ -209,8 +209,9 @@ namespace Breeze.Wallet.Controllers ...@@ -209,8 +209,9 @@ namespace Breeze.Wallet.Controllers
}); });
} }
} }
return this.Json(model.Transactions.OrderByDescending(t => t.Timestamp)); model.Transactions = model.Transactions.OrderByDescending(t => t.Timestamp).ToList();
return this.Json(model);
} }
catch (Exception e) catch (Exception e)
{ {
...@@ -221,11 +222,11 @@ namespace Breeze.Wallet.Controllers ...@@ -221,11 +222,11 @@ namespace Breeze.Wallet.Controllers
/// <summary> /// <summary>
/// Gets the balance of a wallet. /// Gets the balance of a wallet.
/// </summary> /// </summary>
/// <param name="model">The name of the wallet.</param> /// <param name="request">The request parameters.</param>
/// <returns></returns> /// <returns></returns>
[Route("balance")] [Route("balance")]
[HttpGet] [HttpGet]
public IActionResult GetBalance([FromQuery] WalletName model) public IActionResult GetBalance([FromQuery] WalletBalanceRequest request)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
...@@ -236,8 +237,26 @@ namespace Breeze.Wallet.Controllers ...@@ -236,8 +237,26 @@ namespace Breeze.Wallet.Controllers
try try
{ {
return this.Json(this.walletManager.GetBalance(model.Name)); WalletBalanceModel model = new WalletBalanceModel { AccountsBalances = new List<AccountBalance>() };
var accounts = this.walletManager.GetAccountsByCoinType(request.WalletName, request.CoinType).ToList();
foreach (var account in accounts)
{
var allTransactions = account.ExternalAddresses.SelectMany(a => a.Transactions)
.Concat(account.InternalAddresses.SelectMany(i => i.Transactions)).ToList();
AccountBalance balance = new AccountBalance
{
CoinType = request.CoinType,
Name = account.Name,
HdPath = account.HdPath,
AmountConfirmed = allTransactions.Where(t => t.Confirmed).Sum(t => t.Amount),
AmountUnconfirmed = allTransactions.Where(t => !t.Confirmed).Sum(t => t.Amount)
};
model.AccountsBalances.Add(balance);
}
return this.Json(model);
} }
catch (Exception e) catch (Exception e)
{ {
......
...@@ -71,10 +71,8 @@ namespace Breeze.Wallet ...@@ -71,10 +71,8 @@ namespace Breeze.Wallet
/// <param name="accountName">The name of the account in which this address will be created.</param> /// <param name="accountName">The name of the account in which this address will be created.</param>
/// <returns>The new address, in Base58 format.</returns> /// <returns>The new address, in Base58 format.</returns>
string CreateNewAddress(string walletName, CoinType coinType, string accountName); string CreateNewAddress(string walletName, CoinType coinType, string accountName);
WalletGeneralInfoModel GetGeneralInfo(string walletName);
WalletBalanceModel GetBalance(string walletName); WalletGeneralInfoModel GetGeneralInfo(string walletName);
/// <summary> /// <summary>
/// Gets a list of accounts filtered by coin type. /// Gets a list of accounts filtered by coin type.
......
...@@ -56,6 +56,15 @@ namespace Breeze.Wallet.Models ...@@ -56,6 +56,15 @@ namespace Breeze.Wallet.Models
public CoinType CoinType { get; set; } public CoinType CoinType { get; set; }
} }
public class WalletBalanceRequest
{
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string WalletName { get; set; }
[Required(ErrorMessage = "The type of coin for which history is requested is missing.")]
public CoinType CoinType { get; set; }
}
public class WalletName public class WalletName
{ {
[Required(ErrorMessage = "The name of the wallet is missing.")] [Required(ErrorMessage = "The name of the wallet is missing.")]
......
...@@ -9,13 +9,25 @@ namespace Breeze.Wallet.Models ...@@ -9,13 +9,25 @@ namespace Breeze.Wallet.Models
{ {
public class WalletBalanceModel public class WalletBalanceModel
{ {
[JsonProperty(PropertyName = "isSynced")] [JsonProperty(PropertyName = "balances")]
public bool IsSynced { get; set; } public List<AccountBalance> AccountsBalances { get; set; }
}
[JsonProperty(PropertyName = "confirmed")] public class AccountBalance
public Money Confirmed { get; set; } {
[JsonProperty(PropertyName = "accountName")]
public string Name { get; set; }
[JsonProperty(PropertyName = "accountHdPath")]
public string HdPath { get; set; }
[JsonProperty(PropertyName = "coinType")]
public CoinType CoinType { get; set; }
[JsonProperty(PropertyName = "amountConfirmed")]
public Money AmountConfirmed { get; set; }
[JsonProperty(PropertyName = "unconfirmed")] [JsonProperty(PropertyName = "amountUnconfirmed")]
public Money Unconfirmed { get; set; } public Money AmountUnconfirmed { get; set; }
} }
} }
...@@ -125,6 +125,13 @@ namespace Breeze.Wallet ...@@ -125,6 +125,13 @@ namespace Breeze.Wallet
[JsonProperty(PropertyName = "name")] [JsonProperty(PropertyName = "name")]
public string Name { get; set; } public string Name { get; set; }
/// <summary>
/// A path to the account as defined in BIP44.
/// </summary>
[JsonProperty(PropertyName = "hdPath")]
public string HdPath { get; set; }
/// <summary> /// <summary>
/// An extended pub key used to generate addresses. /// An extended pub key used to generate addresses.
/// </summary> /// </summary>
......
...@@ -127,7 +127,8 @@ namespace Breeze.Wallet ...@@ -127,7 +127,8 @@ namespace Breeze.Wallet
// get the extended pub key used to generate addresses for this account // get the extended pub key used to generate addresses for this account
var privateKey = Key.Parse(wallet.EncryptedSeed, password, wallet.Network); var privateKey = Key.Parse(wallet.EncryptedSeed, password, wallet.Network);
var seedExtKey = new ExtKey(privateKey, wallet.ChainCode); var seedExtKey = new ExtKey(privateKey, wallet.ChainCode);
KeyPath keyPath = new KeyPath($"m/44'/{(int)coinType}'/{newAccountIndex}'"); var accountHdPath = $"m/44'/{(int) coinType}'/{newAccountIndex}'";
KeyPath keyPath = new KeyPath(accountHdPath);
ExtKey accountExtKey = seedExtKey.Derive(keyPath); ExtKey accountExtKey = seedExtKey.Derive(keyPath);
ExtPubKey accountExtPubKey = accountExtKey.Neuter(); ExtPubKey accountExtPubKey = accountExtKey.Neuter();
...@@ -138,6 +139,7 @@ namespace Breeze.Wallet ...@@ -138,6 +139,7 @@ namespace Breeze.Wallet
ExternalAddresses = new List<HdAddress>(), ExternalAddresses = new List<HdAddress>(),
InternalAddresses = new List<HdAddress>(), InternalAddresses = new List<HdAddress>(),
Name = accountName, Name = accountName,
HdPath = accountHdPath,
CreationTime = DateTimeOffset.Now CreationTime = DateTimeOffset.Now
}); });
...@@ -206,17 +208,12 @@ namespace Breeze.Wallet ...@@ -206,17 +208,12 @@ namespace Breeze.Wallet
throw new System.NotImplementedException(); throw new System.NotImplementedException();
} }
public WalletBalanceModel GetBalance(string walletName)
{
throw new System.NotImplementedException();
}
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<HdAccount> GetAccountsByCoinType(string walletName, CoinType coinType) public IEnumerable<HdAccount> GetAccountsByCoinType(string walletName, CoinType coinType)
{ {
return this.Wallets. return this.Wallets.
SelectMany(w => w.AccountsRoot.Where(a => a.CoinType == coinType)). SelectMany(w => w.AccountsRoot.Where(a => a.CoinType == coinType)).
SelectMany(a => a.Accounts); SelectMany(a => a.Accounts);
} }
public WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType, bool allowUnconfirmed) public WalletBuildTransactionModel BuildTransaction(string password, string address, Money amount, string feeType, bool allowUnconfirmed)
...@@ -253,7 +250,7 @@ namespace Breeze.Wallet ...@@ -253,7 +250,7 @@ namespace Breeze.Wallet
public void ProcessTransaction(CoinType coinType, Transaction transaction, int? blockHeight = null, uint? blockTime = null) public void ProcessTransaction(CoinType coinType, Transaction transaction, int? blockHeight = null, uint? blockTime = null)
{ {
Console.WriteLine($"transaction notification: tx hash {transaction.GetHash()}, coin type: {coinType}"); Console.WriteLine($"transaction notification: tx hash {transaction.GetHash()}, coin type: {coinType}");
foreach (var k in this.PubKeys) foreach (var k in this.PubKeys)
{ {
// check if the outputs contain one of our addresses // check if the outputs contain one of our addresses
...@@ -270,7 +267,7 @@ namespace Breeze.Wallet ...@@ -270,7 +267,7 @@ namespace Breeze.Wallet
// compare the index of the output in its original transaction and the index references in the input // compare the index of the output in its original transaction and the index references in the input
if (input.PrevOut.N == tTx.Index) if (input.PrevOut.N == tTx.Index)
{ {
AddTransactionToWallet(coinType, transaction.GetHash(), transaction.Time, null, -tTx.Amount, k, blockHeight, blockTime); AddTransactionToWallet(coinType, transaction.GetHash(), transaction.Time, null, -tTx.Amount, k, blockHeight, blockTime);
} }
} }
...@@ -488,7 +485,7 @@ namespace Breeze.Wallet ...@@ -488,7 +485,7 @@ namespace Breeze.Wallet
SelectMany(a => a.ExternalAddresses). SelectMany(a => a.ExternalAddresses).
Select(s => s.ScriptPubKey)); Select(s => s.ScriptPubKey));
// uncomment the following for testing on a random address // uncomment the following for testing on a random address
// Select(t => (new BitcoinPubKeyAddress(t.Address, Network.Main)).ScriptPubKey)); // Select(t => (new BitcoinPubKeyAddress(t.Address, Network.Main)).ScriptPubKey));
} }
/// <summary> /// <summary>
......
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