2017-10-06 10:37:38 +09:00
|
|
|
|
using NBitcoin;
|
2017-09-13 15:47:34 +09:00
|
|
|
|
using NBXplorer;
|
|
|
|
|
using NBXplorer.DerivationStrategy;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
2017-10-06 10:37:38 +09:00
|
|
|
|
using BTCPayServer.Data;
|
2018-01-07 02:16:42 +09:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using NBXplorer.Models;
|
2017-09-13 15:47:34 +09:00
|
|
|
|
|
2017-09-15 16:06:57 +09:00
|
|
|
|
namespace BTCPayServer.Services.Wallets
|
2017-09-13 15:47:34 +09:00
|
|
|
|
{
|
2018-01-07 02:16:42 +09:00
|
|
|
|
public class KnownState
|
|
|
|
|
{
|
|
|
|
|
public uint256 UnconfirmedHash { get; set; }
|
|
|
|
|
public uint256 ConfirmedHash { get; set; }
|
|
|
|
|
}
|
|
|
|
|
public class GetCoinsResult
|
|
|
|
|
{
|
|
|
|
|
public Coin[] Coins { get; set; }
|
|
|
|
|
public KnownState State { get; set; }
|
|
|
|
|
public DerivationStrategy Strategy { get; set; }
|
|
|
|
|
}
|
2017-10-27 17:53:04 +09:00
|
|
|
|
public class BTCPayWallet
|
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
private ExplorerClientProvider _Client;
|
2017-10-27 17:53:04 +09:00
|
|
|
|
ApplicationDbContextFactory _DBFactory;
|
|
|
|
|
|
2018-01-08 02:36:41 +09:00
|
|
|
|
public BTCPayWallet(ExplorerClientProvider client, ApplicationDbContextFactory factory)
|
2017-10-27 17:53:04 +09:00
|
|
|
|
{
|
|
|
|
|
if (client == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(client));
|
|
|
|
|
if (factory == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(factory));
|
|
|
|
|
_Client = client;
|
|
|
|
|
_DBFactory = factory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-01-06 18:57:56 +09:00
|
|
|
|
public async Task<BitcoinAddress> ReserveAddressAsync(DerivationStrategy derivationStrategy)
|
2017-10-27 17:53:04 +09:00
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(derivationStrategy.Network);
|
|
|
|
|
var pathInfo = await client.GetUnusedAsync(derivationStrategy.DerivationStrategyBase, DerivationFeature.Deposit, 0, true).ConfigureAwait(false);
|
|
|
|
|
return pathInfo.ScriptPubKey.GetDestinationAddress(client.Network);
|
2017-10-27 17:53:04 +09:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-06 18:57:56 +09:00
|
|
|
|
public async Task TrackAsync(DerivationStrategy derivationStrategy)
|
2017-10-27 17:53:04 +09:00
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(derivationStrategy.Network);
|
|
|
|
|
await client.TrackAsync(derivationStrategy.DerivationStrategyBase);
|
2017-10-27 17:53:04 +09:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-08 02:36:41 +09:00
|
|
|
|
public Task<TransactionResult> GetTransactionAsync(BTCPayNetwork network, uint256 txId, CancellationToken cancellation = default(CancellationToken))
|
2018-01-07 02:16:42 +09:00
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(network);
|
|
|
|
|
return client.GetTransactionAsync(txId, cancellation);
|
2018-01-07 02:16:42 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<GetCoinsResult> GetCoins(DerivationStrategy strategy, KnownState state, CancellationToken cancellation = default(CancellationToken))
|
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(strategy.Network);
|
|
|
|
|
var changes = await client.SyncAsync(strategy.DerivationStrategyBase, state?.ConfirmedHash, state?.UnconfirmedHash, true, cancellation).ConfigureAwait(false);
|
2018-01-07 02:16:42 +09:00
|
|
|
|
var utxos = changes.Confirmed.UTXOs.Concat(changes.Unconfirmed.UTXOs).Select(c => c.AsCoin()).ToArray();
|
|
|
|
|
return new GetCoinsResult()
|
|
|
|
|
{
|
|
|
|
|
Coins = utxos,
|
|
|
|
|
State = new KnownState() { ConfirmedHash = changes.Confirmed.Hash, UnconfirmedHash = changes.Unconfirmed.Hash },
|
|
|
|
|
Strategy = strategy,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-08 02:36:41 +09:00
|
|
|
|
public Task BroadcastTransactionsAsync(BTCPayNetwork network, List<Transaction> transactions)
|
2017-10-27 17:53:04 +09:00
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(network);
|
|
|
|
|
var tasks = transactions.Select(t => client.BroadcastAsync(t)).ToArray();
|
2017-10-27 17:53:04 +09:00
|
|
|
|
return Task.WhenAll(tasks);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-06 18:57:56 +09:00
|
|
|
|
public async Task<Money> GetBalance(DerivationStrategy derivationStrategy)
|
2017-10-27 17:53:04 +09:00
|
|
|
|
{
|
2018-01-08 02:36:41 +09:00
|
|
|
|
var client = _Client.GetExplorerClient(derivationStrategy.Network);
|
|
|
|
|
var result = await client.SyncAsync(derivationStrategy.DerivationStrategyBase, null, true);
|
2018-01-04 22:43:28 +09:00
|
|
|
|
return result.Confirmed.UTXOs.Select(u => u.Value)
|
|
|
|
|
.Concat(result.Unconfirmed.UTXOs.Select(u => u.Value))
|
2017-10-27 17:53:04 +09:00
|
|
|
|
.Sum();
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 15:47:34 +09:00
|
|
|
|
}
|