Decouple the CreateInvoiceCore from BitpayCreateInvoice, remove some features from greenfield invoice for now

This commit is contained in:
nicolas.dorier 2020-08-26 14:01:39 +09:00
parent b2ff041ec0
commit 67b04473b5
No known key found for this signature in database
GPG key ID: 6618763EF09186FE
13 changed files with 135 additions and 126 deletions

View file

@ -4,13 +4,38 @@ using Newtonsoft.Json;
namespace BTCPayServer.Client.JsonConverters
{
public class TimeSpanJsonConverter : JsonConverter
public abstract class TimeSpanJsonConverter : JsonConverter
{
public class Seconds : TimeSpanJsonConverter
{
protected override long ToLong(TimeSpan value)
{
return (long)value.TotalSeconds;
}
protected override TimeSpan ToTimespan(long value)
{
return TimeSpan.FromSeconds(value);
}
}
public class Minutes : TimeSpanJsonConverter
{
protected override long ToLong(TimeSpan value)
{
return (long)value.TotalMinutes;
}
protected override TimeSpan ToTimespan(long value)
{
return TimeSpan.FromMinutes(value);
}
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(TimeSpan) || objectType == typeof(TimeSpan?);
}
protected abstract TimeSpan ToTimespan(long value);
protected abstract long ToLong(TimeSpan value);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
@ -24,11 +49,11 @@ namespace BTCPayServer.Client.JsonConverters
}
if (reader.TokenType != JsonToken.Integer)
throw new JsonObjectException("Invalid timespan, expected integer", reader);
return TimeSpan.FromSeconds((long)reader.Value);
return ToTimespan((long)reader.Value);
}
catch
{
throw new JsonObjectException("Invalid locktime", reader);
throw new JsonObjectException("Invalid timespan", reader);
}
}
@ -36,7 +61,7 @@ namespace BTCPayServer.Client.JsonConverters
{
if (value is TimeSpan s)
{
writer.WriteValue((long)s.TotalSeconds);
writer.WriteValue(ToLong(s));
}
}
}

View file

@ -1,4 +1,5 @@
using System;
using BTCPayServer.Client.JsonConverters;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@ -20,12 +21,13 @@ namespace BTCPayServer.Client.Models
public SpeedPolicy? SpeedPolicy { get; set; }
public string[] PaymentMethods { get; set; }
public bool? RedirectAutomatically { get; set; }
public string RedirectUri { get; set; }
public Uri WebHook { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? ExpirationTime { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
[JsonProperty("expirationMinutes")]
public TimeSpan? Expiration { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
[JsonProperty("monitoringMinutes")]
public TimeSpan? Monitoring { get; set; }
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
public double? PaymentTolerance { get; set; }

View file

@ -20,7 +20,7 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(LightMoneyJsonConverter))]
public LightMoney Amount { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(JsonConverters.TimeSpanJsonConverter))]
[JsonConverter(typeof(JsonConverters.TimeSpanJsonConverter.Seconds))]
public TimeSpan Expiry { get; set; }
public bool PrivateRouteHints { get; set; }

View file

@ -11,7 +11,7 @@ namespace BTCPayServer.Client.Models
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
public string Currency { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter))]
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
public TimeSpan? Period { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? ExpiresAt { get; set; }

View file

@ -16,7 +16,7 @@ namespace BTCPayServer.Client.Models
public string Currency { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter))]
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
public TimeSpan? Period { get; set; }
public bool Archived { get; set; }
public string ViewLink { get; set; }

View file

@ -16,11 +16,11 @@ namespace BTCPayServer.Client.Models
public string Website { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter))]
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public TimeSpan InvoiceExpiration { get; set; } = TimeSpan.FromMinutes(15);
[JsonConverter(typeof(TimeSpanJsonConverter))]
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public TimeSpan MonitoringExpiration { get; set; } = TimeSpan.FromMinutes(60);

View file

@ -125,10 +125,10 @@ namespace BTCPayServer.Controllers.GreenField
}
}
if (request.Checkout.ExpirationTime != null && request.Checkout.ExpirationTime < DateTime.Now)
if (request.Checkout.Expiration != null && request.Checkout.Expiration < TimeSpan.FromSeconds(30.0))
{
request.AddModelError(invoiceRequest => invoiceRequest.Checkout.ExpirationTime,
"Expiration time must be in the future", this);
request.AddModelError(invoiceRequest => invoiceRequest.Checkout.Expiration,
"Expiration time must be at least 30 seconds", this);
}
if (request.Checkout.PaymentTolerance != null &&
@ -143,7 +143,7 @@ namespace BTCPayServer.Controllers.GreenField
try
{
var invoice = await _invoiceController.CreateInvoiceCoreRaw(FromModel(request), store,
var invoice = await _invoiceController.CreateInvoiceCoreRaw(request, store,
Request.GetAbsoluteUri(""));
return Ok(ToModel(invoice));
}
@ -263,14 +263,12 @@ namespace BTCPayServer.Controllers.GreenField
Metadata = entity.Metadata.ToJObject(),
Checkout = new CreateInvoiceRequest.CheckoutOptions()
{
ExpirationTime = entity.ExpirationTime,
Expiration = entity.ExpirationTime - entity.InvoiceTime,
Monitoring = entity.MonitoringExpiration - entity.ExpirationTime,
PaymentTolerance = entity.PaymentTolerance,
PaymentMethods =
entity.GetPaymentMethods().Select(method => method.GetId().ToString()).ToArray(),
RedirectAutomatically = entity.RedirectAutomatically,
RedirectUri = entity.RedirectURL?.ToString(),
SpeedPolicy = entity.SpeedPolicy,
WebHook = entity.NotificationURL
SpeedPolicy = entity.SpeedPolicy
},
PaymentMethodData = entity.GetPaymentMethods().ToDictionary(method => method.GetId().ToString(),
method =>
@ -317,47 +315,5 @@ namespace BTCPayServer.Controllers.GreenField
})
};
}
private Models.BitpayCreateInvoiceRequest FromModel(CreateInvoiceRequest entity)
{
InvoiceMetadata invoiceMetadata = null;
if (entity.Metadata != null)
{
invoiceMetadata = entity.Metadata.ToObject<InvoiceMetadata>();
}
return new Models.BitpayCreateInvoiceRequest()
{
Buyer = invoiceMetadata == null ? null : new Buyer()
{
Address1 = invoiceMetadata.BuyerAddress1,
Address2 = invoiceMetadata.BuyerAddress2,
City = invoiceMetadata.BuyerCity,
country = invoiceMetadata.BuyerCountry,
email = invoiceMetadata.BuyerEmail,
Name = invoiceMetadata.BuyerName,
phone = invoiceMetadata.BuyerPhone,
State = invoiceMetadata.BuyerState,
zip = invoiceMetadata.BuyerZip,
},
Currency = entity.Currency,
Price = entity.Amount,
Refundable = true,
ExtendedNotifications = true,
FullNotifications = true,
RedirectURL = entity.Checkout.RedirectUri,
RedirectAutomatically = entity.Checkout.RedirectAutomatically,
ExpirationTime = entity.Checkout.ExpirationTime,
TransactionSpeed = entity.Checkout.SpeedPolicy?.ToString(),
PaymentCurrencies = entity.Checkout.PaymentMethods,
NotificationURL = entity.Checkout.RedirectUri,
PosData = invoiceMetadata?.PosData,
Physical = invoiceMetadata?.Physical ?? false,
ItemCode = invoiceMetadata?.ItemCode,
ItemDesc = invoiceMetadata?.ItemDesc,
TaxIncluded = invoiceMetadata?.TaxIncluded,
OrderId = invoiceMetadata?.OrderId,
Metadata = entity.Metadata
};
}
}
}

View file

@ -124,8 +124,8 @@ namespace BTCPayServer.Controllers.GreenField
ShowRecommendedFee = storeBlob.ShowRecommendedFee,
RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget,
DefaultLang = storeBlob.DefaultLang,
MonitoringExpiration = TimeSpan.FromMinutes(storeBlob.MonitoringExpiration),
InvoiceExpiration = TimeSpan.FromMinutes(storeBlob.InvoiceExpiration),
MonitoringExpiration = storeBlob.MonitoringExpiration,
InvoiceExpiration = storeBlob.InvoiceExpiration,
LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi,
CustomLogo = storeBlob.CustomLogo,
CustomCSS = storeBlob.CustomCSS,
@ -160,8 +160,8 @@ namespace BTCPayServer.Controllers.GreenField
blob.ShowRecommendedFee = restModel.ShowRecommendedFee;
blob.RecommendedFeeBlockTarget = restModel.RecommendedFeeBlockTarget;
blob.DefaultLang = restModel.DefaultLang;
blob.MonitoringExpiration = (int)restModel.MonitoringExpiration.TotalMinutes;
blob.InvoiceExpiration = (int)restModel.InvoiceExpiration.TotalMinutes;
blob.MonitoringExpiration = restModel.MonitoringExpiration;
blob.InvoiceExpiration = restModel.InvoiceExpiration;
blob.LightningAmountInSatoshi = restModel.LightningAmountInSatoshi;
blob.CustomLogo = restModel.CustomLogo;
blob.CustomCSS = restModel.CustomCSS;

View file

@ -21,6 +21,7 @@ using BTCPayServer.Services.Stores;
using BTCPayServer.Validation;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using NBitpayClient;
using Newtonsoft.Json;
using BitpayCreateInvoiceRequest = BTCPayServer.Models.BitpayCreateInvoiceRequest;
@ -78,41 +79,31 @@ namespace BTCPayServer.Controllers
{
var entity = await CreateInvoiceCoreRaw(invoice, store, serverUrl, additionalTags, cancellationToken);
var resp = entity.EntityToDTO();
return new DataWrapper<InvoiceResponse>(resp) {Facade = "pos/invoice"};
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
{
invoice.Currency = invoice.Currency?.ToUpperInvariant() ?? "USD";
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting");
var entity = _InvoiceRepository.CreateNewInvoice();
var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);
var storeBlob = store.GetStoreBlob();
EmailAddressAttribute emailValidator = new EmailAddressAttribute();
entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration);
var entity = _InvoiceRepository.CreateNewInvoice();
entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime + storeBlob.InvoiceExpiration;
entity.MonitoringExpiration = entity.ExpirationTime + storeBlob.MonitoringExpiration;
if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime)
{
throw new BitpayHttpException(400, "The expirationTime is set too soon");
}
entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration);
invoice.Currency = invoice.Currency?.ToUpperInvariant() ?? "USD";
entity.Currency = invoice.Currency;
entity.Metadata.OrderId = invoice.OrderId;
entity.Metadata.PosData = invoice.PosData;
entity.ServerUrl = serverUrl;
entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications;
entity.ExtendedNotifications = invoice.ExtendedNotifications;
entity.NotificationURLTemplate = invoice.NotificationURL;
entity.NotificationEmail = invoice.NotificationEmail;
entity.PaymentTolerance = storeBlob.PaymentTolerance;
if (additionalTags != null)
entity.InternalTags.AddRange(additionalTags);
FillBuyerInfo(invoice, entity);
if (entity.Metadata.BuyerEmail != null)
{
if (!EmailValidator.IsEmail(entity.Metadata.BuyerEmail))
throw new BitpayHttpException(400, "Invalid email");
entity.RefundMail = entity.Metadata.BuyerEmail;
}
var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m;
@ -127,7 +118,6 @@ namespace BTCPayServer.Controllers
invoice.Price = Math.Max(0.0m, invoice.Price);
invoice.TaxIncluded = Math.Max(0.0m, taxIncluded);
invoice.TaxIncluded = Math.Min(taxIncluded, invoice.Price);
entity.Metadata.ItemCode = invoice.ItemCode;
entity.Metadata.ItemDesc = invoice.ItemDesc;
entity.Metadata.Physical = invoice.Physical;
@ -135,29 +125,12 @@ namespace BTCPayServer.Controllers
entity.Currency = invoice.Currency;
entity.Price = invoice.Price;
if (invoice.Metadata != null)
{
var currentMetadata = entity.Metadata.ToJObject();
foreach (var prop in invoice.Metadata.Properties())
{
if (!currentMetadata.ContainsKey(prop.Name))
currentMetadata.Add(prop.Name, prop.Value);
}
entity.Metadata = InvoiceMetadata.FromJObject(currentMetadata);
}
entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite;
entity.RedirectAutomatically =
invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically);
entity.Status = InvoiceStatus.New;
entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);
HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>();
var rules = storeBlob.GetRateRules(_NetworkProvider);
var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()
IPaymentFilter excludeFilter = null;
if (invoice.PaymentCurrencies?.Any() is true)
{
invoice.SupportedTransactionCurrencies ??=
@ -173,17 +146,67 @@ namespace BTCPayServer.Controllers
var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies
.Where(c => c.Value.Enabled)
.Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null)
.Where(c => c != null)
.ToHashSet();
excludeFilter = PaymentFilter.Or(excludeFilter,
PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)));
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
}
entity.PaymentTolerance = storeBlob.PaymentTolerance;
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken);
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
{
var storeBlob = store.GetStoreBlob();
var entity = _InvoiceRepository.CreateNewInvoice();
entity.ExpirationTime = entity.InvoiceTime + (invoice.Checkout.Expiration ?? storeBlob.InvoiceExpiration);
entity.MonitoringExpiration = entity.ExpirationTime + (invoice.Checkout.Monitoring ?? storeBlob.MonitoringExpiration);
if (invoice.Metadata != null)
entity.Metadata = InvoiceMetadata.FromJObject(invoice.Metadata);
invoice.Checkout ??= new CreateInvoiceRequest.CheckoutOptions();
entity.Currency = invoice.Currency;
entity.Price = invoice.Amount;
entity.SpeedPolicy = invoice.Checkout.SpeedPolicy ?? store.SpeedPolicy;
IPaymentFilter excludeFilter = null;
if (invoice.Checkout.PaymentMethods != null)
{
var supportedTransactionCurrencies = invoice.Checkout.PaymentMethods
.Select(c => PaymentMethodId.TryParse(c, out var p) ? p : null)
.ToHashSet();
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
}
entity.PaymentTolerance = invoice.Checkout.PaymentTolerance ?? storeBlob.PaymentTolerance;
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken);
}
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, CancellationToken cancellationToken = default)
{
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting");
var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);
var storeBlob = store.GetStoreBlob();
if (entity.Metadata.BuyerEmail != null)
{
if (!EmailValidator.IsEmail(entity.Metadata.BuyerEmail))
throw new BitpayHttpException(400, "Invalid email");
entity.RefundMail = entity.Metadata.BuyerEmail;
}
entity.Status = InvoiceStatus.New;
HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>();
var rules = storeBlob.GetRateRules(_NetworkProvider);
var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()
if (invoicePaymentMethodFilter != null)
{
excludeFilter = PaymentFilter.Or(excludeFilter,
invoicePaymentMethodFilter);
}
foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(s => !excludeFilter.Match(s.PaymentId))
.Select(c => _NetworkProvider.GetNetwork<BTCPayNetworkBase>(c.PaymentId.CryptoCode))
.Where(c => c != null))
{
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, invoice.Currency));
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, entity.Currency));
//TODO: abstract
if (storeBlob.LightningMaxValue != null)
currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, storeBlob.LightningMaxValue.Currency));
@ -195,7 +218,12 @@ namespace BTCPayServer.Controllers
var fetchingByCurrencyPair = _RateProvider.FetchRates(currencyPairsToFetch, rateRules, cancellationToken);
var fetchingAll = WhenAllFetched(logs, fetchingByCurrencyPair);
var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider)
List<ISupportedPaymentMethod> supported = new List<ISupportedPaymentMethod>();
var paymentMethods = new PaymentMethodDictionary();
// This loop ends with .ToList so we are querying all payment methods at once
// instead of sequentially to improve response time
foreach (var o in store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(s => !excludeFilter.Match(s.PaymentId) && _paymentMethodHandlerDictionary.Support(s.PaymentId))
.Select(c =>
(Handler: _paymentMethodHandlerDictionary[c.PaymentId],
@ -205,10 +233,7 @@ namespace BTCPayServer.Controllers
.Select(o =>
(SupportedPaymentMethod: o.SupportedPaymentMethod,
PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler, o.SupportedPaymentMethod, o.Network, entity, store, logs)))
.ToList();
List<ISupportedPaymentMethod> supported = new List<ISupportedPaymentMethod>();
var paymentMethods = new PaymentMethodDictionary();
foreach (var o in supportedPaymentMethods)
.ToList())
{
var paymentMethod = await o.PaymentMethod;
if (paymentMethod == null)
@ -231,7 +256,6 @@ namespace BTCPayServer.Controllers
entity.SetSupportedPaymentMethods(supported);
entity.SetPaymentMethods(paymentMethods);
entity.Metadata.PosData = invoice.PosData;
foreach (var app in await getAppsTaggingStore)
{
entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id));

View file

@ -481,8 +481,8 @@ namespace BTCPayServer.Controllers
vm.SpeedPolicy = store.SpeedPolicy;
vm.CanDelete = _Repo.CanDeleteStores();
AddPaymentMethods(store, storeBlob, vm);
vm.MonitoringExpiration = storeBlob.MonitoringExpiration;
vm.InvoiceExpiration = storeBlob.InvoiceExpiration;
vm.MonitoringExpiration = (int)storeBlob.MonitoringExpiration.TotalMinutes;
vm.InvoiceExpiration = (int)storeBlob.InvoiceExpiration.TotalMinutes;
vm.LightningDescriptionTemplate = storeBlob.LightningDescriptionTemplate;
vm.PaymentTolerance = storeBlob.PaymentTolerance;
vm.PayJoinEnabled = storeBlob.PayJoinEnabled;
@ -579,8 +579,8 @@ namespace BTCPayServer.Controllers
var blob = CurrentStore.GetStoreBlob();
blob.AnyoneCanInvoice = model.AnyoneCanCreateInvoice;
blob.NetworkFeeMode = model.NetworkFeeMode;
blob.MonitoringExpiration = model.MonitoringExpiration;
blob.InvoiceExpiration = model.InvoiceExpiration;
blob.MonitoringExpiration = TimeSpan.FromMinutes(model.MonitoringExpiration);
blob.InvoiceExpiration = TimeSpan.FromMinutes(model.InvoiceExpiration);
blob.LightningDescriptionTemplate = model.LightningDescriptionTemplate ?? string.Empty;
blob.PaymentTolerance = model.PaymentTolerance;
var payjoinChanged = blob.PayJoinEnabled != model.PayJoinEnabled;

View file

@ -195,7 +195,7 @@ namespace BTCPayServer.Data
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal MinimumClaim { get; set; }
public PullPaymentView View { get; set; } = new PullPaymentView();
[JsonConverter(typeof(TimeSpanJsonConverter))]
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
public TimeSpan? Period { get; set; }
[JsonProperty(ItemConverterType = typeof(PaymentMethodIdJsonConverter))]

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using BTCPayServer.Client.JsonConverters;
using BTCPayServer.Client.Models;
using BTCPayServer.JsonConverters;
using BTCPayServer.Payments;
@ -19,8 +20,8 @@ namespace BTCPayServer.Data
{
public StoreBlob()
{
InvoiceExpiration = 15;
MonitoringExpiration = 1440;
InvoiceExpiration = TimeSpan.FromMinutes(15);
MonitoringExpiration = TimeSpan.FromDays(1);
PaymentTolerance = 0;
ShowRecommendedFee = true;
RecommendedFeeBlockTarget = 1;
@ -66,17 +67,19 @@ namespace BTCPayServer.Data
}
public string DefaultLang { get; set; }
[DefaultValue(60)]
[DefaultValue(typeof(TimeSpan), "1.00:00:00")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public int MonitoringExpiration
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
public TimeSpan MonitoringExpiration
{
get;
set;
}
[DefaultValue(15)]
[DefaultValue(typeof(TimeSpan), "00:15:00")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public int InvoiceExpiration
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
public TimeSpan InvoiceExpiration
{
get;
set;

View file

@ -82,6 +82,5 @@ namespace BTCPayServer.Models
//Bitpay compatibility: create invoice in btcpay uses this instead of supportedTransactionCurrencies
[JsonProperty(PropertyName = "paymentCurrencies", DefaultValueHandling = DefaultValueHandling.Ignore)]
public IEnumerable<string> PaymentCurrencies { get; set; }
public JObject Metadata { get; set; }
}
}