mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Refactor the InvoiceAddresses table (#6232)
This commit is contained in:
@@ -133,7 +133,7 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
public string GetTrackedDestination(Script scriptPubKey)
|
public string GetTrackedDestination(Script scriptPubKey)
|
||||||
{
|
{
|
||||||
return scriptPubKey.Hash.ToString() + "#" + CryptoCode.ToUpperInvariant();
|
return scriptPubKey.Hash.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ namespace BTCPayServer.Data
|
|||||||
PaymentRequestData.OnModelCreating(builder, Database);
|
PaymentRequestData.OnModelCreating(builder, Database);
|
||||||
PaymentData.OnModelCreating(builder, Database);
|
PaymentData.OnModelCreating(builder, Database);
|
||||||
PayoutData.OnModelCreating(builder, Database);
|
PayoutData.OnModelCreating(builder, Database);
|
||||||
PendingInvoiceData.OnModelCreating(builder);
|
|
||||||
//PlannedTransaction.OnModelCreating(builder);
|
//PlannedTransaction.OnModelCreating(builder);
|
||||||
PullPaymentData.OnModelCreating(builder, Database);
|
PullPaymentData.OnModelCreating(builder, Database);
|
||||||
RefundData.OnModelCreating(builder);
|
RefundData.OnModelCreating(builder);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace BTCPayServer.Data
|
|||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
public InvoiceData InvoiceData { get; set; }
|
public InvoiceData InvoiceData { get; set; }
|
||||||
public string InvoiceDataId { get; set; }
|
public string InvoiceDataId { get; set; }
|
||||||
|
public string PaymentMethodId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
internal static void OnModelCreating(ModelBuilder builder)
|
internal static void OnModelCreating(ModelBuilder builder)
|
||||||
@@ -18,7 +19,7 @@ namespace BTCPayServer.Data
|
|||||||
.WithMany(i => i.AddressInvoices).OnDelete(DeleteBehavior.Cascade);
|
.WithMany(i => i.AddressInvoices).OnDelete(DeleteBehavior.Cascade);
|
||||||
builder.Entity<AddressInvoiceData>()
|
builder.Entity<AddressInvoiceData>()
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
.HasKey(o => o.Address);
|
.HasKey(o => new { o.PaymentMethodId, o.Address });
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace BTCPayServer.Data
|
|||||||
public string ExceptionStatus { get; set; }
|
public string ExceptionStatus { get; set; }
|
||||||
public List<AddressInvoiceData> AddressInvoices { get; set; }
|
public List<AddressInvoiceData> AddressInvoices { get; set; }
|
||||||
public bool Archived { get; set; }
|
public bool Archived { get; set; }
|
||||||
public List<PendingInvoiceData> PendingInvoices { get; set; }
|
|
||||||
public List<InvoiceSearchData> InvoiceSearchData { get; set; }
|
public List<InvoiceSearchData> InvoiceSearchData { get; set; }
|
||||||
public List<RefundData> Refunds { get; set; }
|
public List<RefundData> Refunds { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace BTCPayServer.Data
|
|
||||||
{
|
|
||||||
public class PendingInvoiceData
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
public InvoiceData InvoiceData { get; set; }
|
|
||||||
|
|
||||||
internal static void OnModelCreating(ModelBuilder builder)
|
|
||||||
{
|
|
||||||
builder.Entity<PendingInvoiceData>()
|
|
||||||
.HasOne(o => o.InvoiceData)
|
|
||||||
.WithMany(o => o.PendingInvoices)
|
|
||||||
.HasForeignKey(o => o.Id).OnDelete(DeleteBehavior.Cascade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using BTCPayServer.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace BTCPayServer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20240919085726_refactorinvoiceaddress")]
|
||||||
|
public partial class refactorinvoiceaddress : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_AddressInvoices",
|
||||||
|
table: "AddressInvoices");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "PaymentMethodId",
|
||||||
|
table: "AddressInvoices",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.Sql("""
|
||||||
|
UPDATE "AddressInvoices"
|
||||||
|
SET
|
||||||
|
"Address" = (string_to_array("Address", '#'))[1],
|
||||||
|
"PaymentMethodId" = CASE WHEN (string_to_array("Address", '#'))[2] IS NULL THEN 'BTC-CHAIN'
|
||||||
|
WHEN STRPOS((string_to_array("Address", '#'))[2], '_') = 0 THEN (string_to_array("Address", '#'))[2] || '-CHAIN'
|
||||||
|
WHEN STRPOS((string_to_array("Address", '#'))[2], '_MoneroLike') > 0 THEN replace((string_to_array("Address", '#'))[2],'_MoneroLike','-CHAIN')
|
||||||
|
WHEN STRPOS((string_to_array("Address", '#'))[2], '_ZcashLike') > 0 THEN replace((string_to_array("Address", '#'))[2],'_ZcashLike','-CHAIN')
|
||||||
|
ELSE '' END;
|
||||||
|
|
||||||
|
DELETE FROM "AddressInvoices" WHERE "PaymentMethodId" = '';
|
||||||
|
""");
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_AddressInvoices",
|
||||||
|
table: "AddressInvoices",
|
||||||
|
columns: new[] { "PaymentMethodId", "Address" });
|
||||||
|
migrationBuilder.Sql("VACUUM (ANALYZE) \"AddressInvoices\";", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_AddressInvoices",
|
||||||
|
table: "AddressInvoices");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PaymentMethodId",
|
||||||
|
table: "AddressInvoices");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_AddressInvoices",
|
||||||
|
table: "AddressInvoices",
|
||||||
|
column: "Address");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PendingInvoices",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PendingInvoices", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PendingInvoices_Invoices_Id",
|
||||||
|
column: x => x.Id,
|
||||||
|
principalTable: "Invoices",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,13 +60,16 @@ namespace BTCPayServer.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
modelBuilder.Entity("BTCPayServer.Data.AddressInvoiceData", b =>
|
||||||
{
|
{
|
||||||
|
b.Property<string>("PaymentMethodId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Address")
|
b.Property<string>("Address")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("InvoiceDataId")
|
b.Property<string>("InvoiceDataId")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("Address");
|
b.HasKey("PaymentMethodId", "Address");
|
||||||
|
|
||||||
b.HasIndex("InvoiceDataId");
|
b.HasIndex("InvoiceDataId");
|
||||||
|
|
||||||
@@ -634,16 +637,6 @@ namespace BTCPayServer.Migrations
|
|||||||
b.ToTable("PayoutProcessors");
|
b.ToTable("PayoutProcessors");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PendingInvoiceData", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Id")
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("PendingInvoices");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PlannedTransaction", b =>
|
modelBuilder.Entity("BTCPayServer.Data.PlannedTransaction", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
@@ -1331,17 +1324,6 @@ namespace BTCPayServer.Migrations
|
|||||||
b.Navigation("Store");
|
b.Navigation("Store");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PendingInvoiceData", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
|
|
||||||
.WithMany("PendingInvoices")
|
|
||||||
.HasForeignKey("Id")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("InvoiceData");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("BTCPayServer.Data.PullPaymentData", b =>
|
modelBuilder.Entity("BTCPayServer.Data.PullPaymentData", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
b.HasOne("BTCPayServer.Data.StoreData", "StoreData")
|
||||||
@@ -1572,8 +1554,6 @@ namespace BTCPayServer.Migrations
|
|||||||
|
|
||||||
b.Navigation("Payments");
|
b.Navigation("Payments");
|
||||||
|
|
||||||
b.Navigation("PendingInvoices");
|
|
||||||
|
|
||||||
b.Navigation("Refunds");
|
b.Navigation("Refunds");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,26 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CanMigrateInvoiceAddresses()
|
||||||
|
{
|
||||||
|
var tester = CreateDBTester();
|
||||||
|
await tester.MigrateUntil("20240919085726_refactorinvoiceaddress");
|
||||||
|
using var ctx = tester.CreateContext();
|
||||||
|
var conn = ctx.Database.GetDbConnection();
|
||||||
|
await conn.ExecuteAsync("INSERT INTO \"Invoices\" (\"Id\", \"Created\") VALUES ('i', NOW())");
|
||||||
|
await conn.ExecuteAsync(
|
||||||
|
"INSERT INTO \"AddressInvoices\" VALUES ('aaa#BTC', 'i'),('bbb','i'),('ccc#BTC_LNU', 'i'),('ddd#XMR_MoneroLike', 'i'),('eee#ZEC_ZcashLike', 'i')");
|
||||||
|
await tester.ContinueMigration();
|
||||||
|
foreach (var v in new[] { ("aaa", "BTC-CHAIN"), ("bbb", "BTC-CHAIN"), ("ddd", "XMR-CHAIN") , ("eee", "ZEC-CHAIN") })
|
||||||
|
{
|
||||||
|
var ok = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"AddressInvoices\" WHERE \"Address\"=@a AND \"PaymentMethodId\"=@b", new { a = v.Item1, b = v.Item2 });
|
||||||
|
Assert.True(ok);
|
||||||
|
}
|
||||||
|
var notok = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"AddressInvoices\" WHERE \"Address\"='ccc'");
|
||||||
|
Assert.False(notok);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanMigratePayoutsAndPullPayments()
|
public async Task CanMigratePayoutsAndPullPayments()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace BTCPayServer.Tests
|
|||||||
public static class TestUtils
|
public static class TestUtils
|
||||||
{
|
{
|
||||||
#if DEBUG && !SHORT_TIMEOUT
|
#if DEBUG && !SHORT_TIMEOUT
|
||||||
public const int TestTimeout = 600_000;
|
public const int TestTimeout = 60_000;
|
||||||
#else
|
#else
|
||||||
public const int TestTimeout = 90_000;
|
public const int TestTimeout = 90_000;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2449,9 +2449,10 @@ namespace BTCPayServer.Tests
|
|||||||
private static bool IsMapped(Invoice invoice, ApplicationDbContext ctx)
|
private static bool IsMapped(Invoice invoice, ApplicationDbContext ctx)
|
||||||
{
|
{
|
||||||
var h = BitcoinAddress.Create(invoice.BitcoinAddress, Network.RegTest).ScriptPubKey.Hash.ToString();
|
var h = BitcoinAddress.Create(invoice.BitcoinAddress, Network.RegTest).ScriptPubKey.Hash.ToString();
|
||||||
|
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||||
return (ctx.AddressInvoices.Where(i => i.InvoiceDataId == invoice.Id).ToArrayAsync().GetAwaiter()
|
return (ctx.AddressInvoices.Where(i => i.InvoiceDataId == invoice.Id).ToArrayAsync().GetAwaiter()
|
||||||
.GetResult())
|
.GetResult())
|
||||||
.Where(i => i.GetAddress() == h).Any();
|
.Where(i => i.Address == h && i.PaymentMethodId == pmi.ToString()).Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -649,9 +649,7 @@ namespace BTCPayServer.Controllers
|
|||||||
if (derivationScheme is null)
|
if (derivationScheme is null)
|
||||||
return NotSupported("This feature is only available to BTC wallets");
|
return NotSupported("This feature is only available to BTC wallets");
|
||||||
var btc = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
var btc = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||||
var bumpableAddresses = (await GetAddresses(selectedItems))
|
var bumpableAddresses = await GetAddresses(btc, selectedItems);
|
||||||
.Where(p => p.GetPaymentMethodId() == btc)
|
|
||||||
.Select(p => p.GetAddress()).ToHashSet();
|
|
||||||
var utxos = await explorer.GetUTXOsAsync(derivationScheme);
|
var utxos = await explorer.GetUTXOsAsync(derivationScheme);
|
||||||
var bumpableUTXOs = utxos.GetUnspentUTXOs().Where(u => u.Confirmations == 0 && bumpableAddresses.Contains(u.ScriptPubKey.Hash.ToString())).ToArray();
|
var bumpableUTXOs = utxos.GetUnspentUTXOs().Where(u => u.Confirmations == 0 && bumpableAddresses.Contains(u.ScriptPubKey.Hash.ToString())).ToArray();
|
||||||
var parameters = new MultiValueDictionary<string, string>();
|
var parameters = new MultiValueDictionary<string, string>();
|
||||||
@@ -673,10 +671,10 @@ namespace BTCPayServer.Controllers
|
|||||||
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
return RedirectToAction(nameof(ListInvoices), new { storeId });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AddressInvoiceData[]> GetAddresses(string[] selectedItems)
|
private async Task<HashSet<string>> GetAddresses(PaymentMethodId paymentMethodId, string[] selectedItems)
|
||||||
{
|
{
|
||||||
using var ctx = _dbContextFactory.CreateContext();
|
using var ctx = _dbContextFactory.CreateContext();
|
||||||
return await ctx.AddressInvoices.Where(i => selectedItems.Contains(i.InvoiceDataId)).ToArrayAsync();
|
return new HashSet<string>(await ctx.AddressInvoices.Where(i => i.PaymentMethodId == paymentMethodId.ToString() && selectedItems.Contains(i.InvoiceDataId)).Select(i => i.Address).ToArrayAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("i/{invoiceId}")]
|
[HttpGet("i/{invoiceId}")]
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BTCPayServer.Payments;
|
|
||||||
|
|
||||||
namespace BTCPayServer.Data
|
|
||||||
{
|
|
||||||
public static class AddressInvoiceDataExtensions
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0618
|
|
||||||
public static string GetAddress(this AddressInvoiceData addressInvoiceData)
|
|
||||||
{
|
|
||||||
if (addressInvoiceData.Address == null)
|
|
||||||
return null;
|
|
||||||
var index = addressInvoiceData.Address.LastIndexOf("#", StringComparison.InvariantCulture);
|
|
||||||
if (index == -1)
|
|
||||||
return addressInvoiceData.Address;
|
|
||||||
return addressInvoiceData.Address.Substring(0, index);
|
|
||||||
}
|
|
||||||
public static PaymentMethodId GetPaymentMethodId(this AddressInvoiceData addressInvoiceData)
|
|
||||||
{
|
|
||||||
if (addressInvoiceData.Address == null)
|
|
||||||
return null;
|
|
||||||
var index = addressInvoiceData.Address.LastIndexOf("#", StringComparison.InvariantCulture);
|
|
||||||
// Legacy AddressInvoiceData does not have the paymentMethodId attached to the Address
|
|
||||||
if (index == -1)
|
|
||||||
return PaymentMethodId.Parse("BTC");
|
|
||||||
/////////////////////////
|
|
||||||
return PaymentMethodId.TryParse(addressInvoiceData.Address.Substring(index + 1));
|
|
||||||
}
|
|
||||||
#pragma warning restore CS0618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -73,7 +73,7 @@ namespace BTCPayServer.Data
|
|||||||
entity.Status = state.Status;
|
entity.Status = state.Status;
|
||||||
if (invoiceData.AddressInvoices != null)
|
if (invoiceData.AddressInvoices != null)
|
||||||
{
|
{
|
||||||
entity.AvailableAddressHashes = invoiceData.AddressInvoices.Select(a => a.GetAddress() + a.GetPaymentMethodId()).ToHashSet();
|
entity.Addresses = invoiceData.AddressInvoices.Select(a => (PaymentMethodId.Parse(a.PaymentMethodId), a.Address)).ToHashSet();
|
||||||
}
|
}
|
||||||
if (invoiceData.Refunds != null)
|
if (invoiceData.Refunds != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
Logs.PayServer.LogInformation($"{network.CryptoCode}: {paymentCount} payments happened while offline");
|
Logs.PayServer.LogInformation($"{network.CryptoCode}: {paymentCount} payments happened while offline");
|
||||||
|
|
||||||
Logs.PayServer.LogInformation($"Connected to WebSocket of NBXplorer ({network.CryptoCode})");
|
Logs.PayServer.LogInformation($"Connected to WebSocket of NBXplorer ({network.CryptoCode})");
|
||||||
|
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
||||||
while (!_Cts.IsCancellationRequested)
|
while (!_Cts.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var newEvent = await session.NextEventAsync(_Cts.Token).ConfigureAwait(false);
|
var newEvent = await session.NextEventAsync(_Cts.Token).ConfigureAwait(false);
|
||||||
@@ -163,13 +164,11 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
foreach (var output in validOutputs)
|
foreach (var output in validOutputs)
|
||||||
{
|
{
|
||||||
var key = network.GetTrackedDestination(output.Item1.ScriptPubKey);
|
var key = network.GetTrackedDestination(output.Item1.ScriptPubKey);
|
||||||
var invoice = (await _InvoiceRepository.GetInvoicesFromAddresses(new[] { key }))
|
var invoice = await _InvoiceRepository.GetInvoiceFromAddress(pmi, key);
|
||||||
.FirstOrDefault();
|
|
||||||
if (invoice != null)
|
if (invoice != null)
|
||||||
{
|
{
|
||||||
var address = output.matchedOutput.Address ?? network.NBXplorerNetwork.CreateAddress(evt.DerivationStrategy,
|
var address = output.matchedOutput.Address ?? network.NBXplorerNetwork.CreateAddress(evt.DerivationStrategy,
|
||||||
output.Item1.KeyPath, output.Item1.ScriptPubKey);
|
output.Item1.KeyPath, output.Item1.ScriptPubKey);
|
||||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
|
|
||||||
var handler = _handlers[pmi];
|
var handler = _handlers[pmi];
|
||||||
var details = new BitcoinLikePaymentData(output.outPoint, evt.TransactionData.Transaction.RBF, output.matchedOutput.KeyPath);
|
var details = new BitcoinLikePaymentData(output.outPoint, evt.TransactionData.Transaction.RBF, output.matchedOutput.KeyPath);
|
||||||
|
|
||||||
@@ -198,7 +197,6 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
await UpdatePaymentStates(wallet, invoice.Id);
|
await UpdatePaymentStates(wallet, invoice.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,8 +404,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
coins = await wallet.GetUnspentCoins(strategy);
|
coins = await wallet.GetUnspentCoins(strategy);
|
||||||
coinsPerDerivationStrategy.Add(strategy, coins);
|
coinsPerDerivationStrategy.Add(strategy, coins);
|
||||||
}
|
}
|
||||||
coins = coins.Where(c => invoice.AvailableAddressHashes.Contains(c.ScriptPubKey.Hash.ToString() + cryptoId))
|
coins = coins.Where(c => invoice.Addresses.Contains((cryptoId, network.GetTrackedDestination(c.ScriptPubKey)))).ToArray();
|
||||||
.ToArray();
|
|
||||||
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.OutPoint)))
|
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.OutPoint)))
|
||||||
{
|
{
|
||||||
var transaction = await wallet.GetTransactionAsync(coin.OutPoint.Hash);
|
var transaction = await wallet.GetTransactionAsync(coin.OutPoint.Hash);
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ namespace BTCPayServer.Payments
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This string can be used to query AddressInvoice to find the invoiceId
|
/// This string can be used to query AddressInvoice to find the invoiceId
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> TrackedDestinations { get; } = new List<string>();
|
public List<string> TrackedDestinations { get; } = new();
|
||||||
|
|
||||||
internal async Task BeforeFetchingRates()
|
internal async Task BeforeFetchingRates()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -265,8 +265,8 @@ namespace BTCPayServer.Payments.PayJoin
|
|||||||
if (walletReceiveMatch is null)
|
if (walletReceiveMatch is null)
|
||||||
{
|
{
|
||||||
|
|
||||||
var key = output.ScriptPubKey.Hash + "#" + network.CryptoCode.ToUpperInvariant();
|
var key = network.GetTrackedDestination(output.ScriptPubKey);
|
||||||
invoice = (await _invoiceRepository.GetInvoicesFromAddresses(new[] { key })).FirstOrDefault();
|
invoice = await _invoiceRepository.GetInvoiceFromAddress(paymentMethodId, key);
|
||||||
if (invoice is null)
|
if (invoice is null)
|
||||||
continue;
|
continue;
|
||||||
accountDerivation = _handlers.GetDerivationStrategy(invoice, network);
|
accountDerivation = _handlers.GetDerivationStrategy(invoice, network);
|
||||||
|
|||||||
@@ -284,12 +284,9 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
||||||
{
|
{
|
||||||
//find the invoice corresponding to this address, else skip
|
//find the invoice corresponding to this address, else skip
|
||||||
var address = destination.Key + "#" + paymentMethodId;
|
var invoice = await _invoiceRepository.GetInvoiceFromAddress(paymentMethodId, destination.Key);
|
||||||
var invoice = (await _invoiceRepository.GetInvoicesFromAddresses(new[] { address })).FirstOrDefault();
|
|
||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
var index = destination.First().SubaddrIndex;
|
var index = destination.First().SubaddrIndex;
|
||||||
|
|
||||||
|
|||||||
@@ -282,12 +282,9 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Services
|
|||||||
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
foreach (var destination in transfer.Transfers.GroupBy(destination => destination.Address))
|
||||||
{
|
{
|
||||||
//find the invoice corresponding to this address, else skip
|
//find the invoice corresponding to this address, else skip
|
||||||
var address = destination.Key + "#" + paymentMethodId;
|
var invoice = await _invoiceRepository.GetInvoiceFromAddress(paymentMethodId, destination.Key);
|
||||||
var invoice = (await _invoiceRepository.GetInvoicesFromAddresses(new[] { address })).FirstOrDefault();
|
|
||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
var index = destination.First().SubaddrIndex;
|
var index = destination.First().SubaddrIndex;
|
||||||
|
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
public DateTimeOffset MonitoringExpiration { get; set; }
|
public DateTimeOffset MonitoringExpiration { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public HashSet<string> AvailableAddressHashes { get; set; }
|
public HashSet<(PaymentMethodId PaymentMethodId, string Address)> Addresses { get; set; }
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public bool ExtendedNotifications { get; set; }
|
public bool ExtendedNotifications { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -67,29 +67,16 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<InvoiceEntity>> GetInvoicesFromAddresses(string[] addresses)
|
public async Task<InvoiceEntity> GetInvoiceFromAddress(PaymentMethodId paymentMethodId, string address)
|
||||||
{
|
{
|
||||||
if (addresses.Length is 0)
|
|
||||||
return Array.Empty<InvoiceEntity>();
|
|
||||||
using var db = _applicationDbContextFactory.CreateContext();
|
using var db = _applicationDbContextFactory.CreateContext();
|
||||||
if (addresses.Length == 1)
|
var row = (await db.AddressInvoices
|
||||||
{
|
.Include(a => a.InvoiceData.Payments)
|
||||||
var address = addresses[0];
|
.Where(a => a.PaymentMethodId == paymentMethodId.ToString() && a.Address == address)
|
||||||
return (await db.AddressInvoices
|
.Select(a => a.InvoiceData)
|
||||||
.Include(a => a.InvoiceData.Payments)
|
.FirstOrDefaultAsync());
|
||||||
.Where(a => a.Address == address)
|
return row is null ? null : ToEntity(row);
|
||||||
.Select(a => a.InvoiceData)
|
}
|
||||||
.ToListAsync()).Select(ToEntity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (await db.AddressInvoices
|
|
||||||
.Include(a => a.InvoiceData.Payments)
|
|
||||||
.Where(a => addresses.Contains(a.Address))
|
|
||||||
.Select(a => a.InvoiceData)
|
|
||||||
.ToListAsync()).Select(ToEntity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<InvoiceEntity[]> GetInvoicesWithPendingPayments(PaymentMethodId paymentMethodId, bool includeAddresses = false)
|
public async Task<InvoiceEntity[]> GetInvoicesWithPendingPayments(PaymentMethodId paymentMethodId, bool includeAddresses = false)
|
||||||
{
|
{
|
||||||
@@ -190,7 +177,8 @@ retry:
|
|||||||
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
||||||
{
|
{
|
||||||
InvoiceDataId = invoice.Id,
|
InvoiceDataId = invoice.Id,
|
||||||
Address = trackedDestination
|
Address = trackedDestination,
|
||||||
|
PaymentMethodId = ctx.Key.ToString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +299,8 @@ retry:
|
|||||||
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
||||||
{
|
{
|
||||||
InvoiceDataId = invoiceId,
|
InvoiceDataId = invoiceId,
|
||||||
Address = tracked
|
Address = tracked,
|
||||||
|
PaymentMethodId = paymentPromptContext.PaymentMethodId.ToString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AddToTextSearch(context, invoice, prompt.Destination);
|
AddToTextSearch(context, invoice, prompt.Destination);
|
||||||
|
|||||||
Reference in New Issue
Block a user