mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Add OnChainMinValue
This commit is contained in:
@@ -868,6 +868,49 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetPaymentMethodLimits()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.RegisterLightningNode("BTC", LightningConnectionType.Charge);
|
||||
var vm = Assert.IsType<CheckoutExperienceViewModel>(Assert.IsType<ViewResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId).Result).Model);
|
||||
vm.LightningMaxValue = "2 USD";
|
||||
vm.OnChainMinValue = "5 USD";
|
||||
Assert.IsType<RedirectToActionResult>(user.GetController<StoresController>().CheckoutExperience(user.StoreId, vm).Result);
|
||||
|
||||
var invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 1.5,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo);
|
||||
Assert.Equal(PaymentTypes.LightningLike.ToString(), invoice.CryptoInfo[0].PaymentType);
|
||||
|
||||
invoice = user.BitPay.CreateInvoice(new Invoice()
|
||||
{
|
||||
Price = 5.5,
|
||||
Currency = "USD",
|
||||
PosData = "posData",
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Single(invoice.CryptoInfo);
|
||||
Assert.Equal(PaymentTypes.BTCLike.ToString(), invoice.CryptoInfo[0].PaymentType);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanUsePoSApp()
|
||||
{
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
StringBuilder errors = new StringBuilder();
|
||||
errors.AppendLine("No payment method available for this store");
|
||||
foreach(var error in paymentMethodErrors)
|
||||
foreach (var error in paymentMethodErrors)
|
||||
{
|
||||
errors.AppendLine(error);
|
||||
}
|
||||
@@ -196,21 +196,36 @@ namespace BTCPayServer.Controllers
|
||||
paymentDetails.SetNoTxFee();
|
||||
paymentMethod.SetPaymentMethodDetails(paymentDetails);
|
||||
|
||||
// Check if Lightning Max value is exceeded
|
||||
Func<Money, Money, bool> compare = null;
|
||||
CurrencyValue limitValue = null;
|
||||
string errorMessage = null;
|
||||
if (supportedPaymentMethod.PaymentId.PaymentType == PaymentTypes.LightningLike &&
|
||||
storeBlob.LightningMaxValue != null)
|
||||
{
|
||||
var lightningMaxValue = storeBlob.LightningMaxValue;
|
||||
var lightningMaxValueRate = 0.0m;
|
||||
if (lightningMaxValue.Currency == entity.ProductInformation.Currency)
|
||||
lightningMaxValueRate = paymentMethod.Rate;
|
||||
else
|
||||
lightningMaxValueRate = await storeBlob.ApplyRateRules(network, _RateProviders.GetRateProvider(network, false)).GetRateAsync(lightningMaxValue.Currency);
|
||||
compare = (a, b) => a > b;
|
||||
limitValue = storeBlob.LightningMaxValue;
|
||||
errorMessage = "The amount of the invoice is too high to be paid with lightning";
|
||||
}
|
||||
else if (supportedPaymentMethod.PaymentId.PaymentType == PaymentTypes.BTCLike &&
|
||||
storeBlob.OnChainMinValue != null)
|
||||
{
|
||||
compare = (a, b) => a < b;
|
||||
limitValue = storeBlob.OnChainMinValue;
|
||||
errorMessage = "The amount of the invoice is too low to be paid on chain";
|
||||
}
|
||||
|
||||
var lightningMaxValueCrypto = Money.Coins(lightningMaxValue.Value / lightningMaxValueRate);
|
||||
if (paymentMethod.Calculate().Due > lightningMaxValueCrypto)
|
||||
if (compare != null)
|
||||
{
|
||||
var limitValueRate = 0.0m;
|
||||
if (limitValue.Currency == entity.ProductInformation.Currency)
|
||||
limitValueRate = paymentMethod.Rate;
|
||||
else
|
||||
limitValueRate = await storeBlob.ApplyRateRules(network, _RateProviders.GetRateProvider(network, false)).GetRateAsync(limitValue.Currency);
|
||||
|
||||
var limitValueCrypto = Money.Coins(limitValue.Value / limitValueRate);
|
||||
if (compare(paymentMethod.Calculate().Due, limitValueCrypto))
|
||||
{
|
||||
throw new PaymentMethodUnavailableException("Lightning max value exceeded");
|
||||
throw new PaymentMethodUnavailableException(errorMessage);
|
||||
}
|
||||
}
|
||||
///////////////
|
||||
|
||||
@@ -195,6 +195,7 @@ namespace BTCPayServer.Controllers
|
||||
vm.SetCryptoCurrencies(_ExplorerProvider, store.GetDefaultCrypto());
|
||||
vm.SetLanguages(_LangService, storeBlob.DefaultLang);
|
||||
vm.LightningMaxValue = storeBlob.LightningMaxValue?.ToString() ?? "";
|
||||
vm.OnChainMinValue = storeBlob.OnChainMinValue?.ToString() ?? "";
|
||||
vm.AllowCoinConversion = storeBlob.AllowCoinConversion;
|
||||
vm.CustomCSS = storeBlob.CustomCSS;
|
||||
vm.CustomLogo = storeBlob.CustomLogo;
|
||||
@@ -205,14 +206,24 @@ namespace BTCPayServer.Controllers
|
||||
[Route("{storeId}/checkout")]
|
||||
public async Task<IActionResult> CheckoutExperience(string storeId, CheckoutExperienceViewModel model)
|
||||
{
|
||||
CurrencyValue currencyValue = null;
|
||||
CurrencyValue lightningMaxValue = null;
|
||||
if (!string.IsNullOrWhiteSpace(model.LightningMaxValue))
|
||||
{
|
||||
if (!CurrencyValue.TryParse(model.LightningMaxValue, out currencyValue))
|
||||
if (!CurrencyValue.TryParse(model.LightningMaxValue, out lightningMaxValue))
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid currency value");
|
||||
ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid lightning max value");
|
||||
}
|
||||
}
|
||||
|
||||
CurrencyValue onchainMinValue = null;
|
||||
if (!string.IsNullOrWhiteSpace(model.OnChainMinValue))
|
||||
{
|
||||
if (!CurrencyValue.TryParse(model.OnChainMinValue, out onchainMinValue))
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.OnChainMinValue), "Invalid on chain min value");
|
||||
}
|
||||
}
|
||||
|
||||
var store = await _Repo.FindStore(storeId, GetUserId());
|
||||
if (store == null)
|
||||
return NotFound();
|
||||
@@ -227,7 +238,8 @@ namespace BTCPayServer.Controllers
|
||||
model.SetLanguages(_LangService, model.DefaultLang);
|
||||
blob.DefaultLang = model.DefaultLang;
|
||||
blob.AllowCoinConversion = model.AllowCoinConversion;
|
||||
blob.LightningMaxValue = currencyValue;
|
||||
blob.LightningMaxValue = lightningMaxValue;
|
||||
blob.OnChainMinValue = onchainMinValue;
|
||||
blob.CustomLogo = model.CustomLogo;
|
||||
blob.CustomCSS = model.CustomCSS;
|
||||
if (store.SetStoreBlob(blob))
|
||||
|
||||
@@ -262,6 +262,8 @@ namespace BTCPayServer.Data
|
||||
|
||||
[JsonConverter(typeof(CurrencyValueJsonConverter))]
|
||||
public CurrencyValue LightningMaxValue { get; set; }
|
||||
[JsonConverter(typeof(CurrencyValueJsonConverter))]
|
||||
public CurrencyValue OnChainMinValue { get; set; }
|
||||
|
||||
[JsonConverter(typeof(UriJsonConverter))]
|
||||
public Uri CustomLogo { get; set; }
|
||||
|
||||
@@ -31,12 +31,17 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
[MaxLength(20)]
|
||||
public string LightningMaxValue { get; set; }
|
||||
|
||||
[Display(Name = "Do not propose on chain payment if the value of the invoice is below...")]
|
||||
[MaxLength(20)]
|
||||
public string OnChainMinValue { get; set; }
|
||||
|
||||
[Display(Name = "Link to a custom CSS stylesheet")]
|
||||
[Url]
|
||||
public Uri CustomCSS { get; set; }
|
||||
[Display(Name = "Link to a custom logo")]
|
||||
[Url]
|
||||
public Uri CustomLogo { get; set; }
|
||||
|
||||
public void SetCryptoCurrencies(ExplorerClientProvider explorerProvider, string defaultCrypto)
|
||||
{
|
||||
var choices = explorerProvider.GetAll().Select(o => new Format() { Name = o.Item1.CryptoCode, Value = o.Item1.CryptoCode }).ToArray();
|
||||
|
||||
@@ -44,6 +44,12 @@
|
||||
<span asp-validation-for="LightningMaxValue" class="text-danger"></span>
|
||||
<p class="form-text text-muted">Example: 5.50 USD</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="OnChainMinValue"></label>
|
||||
<input asp-for="OnChainMinValue" class="form-control" />
|
||||
<span asp-validation-for="OnChainMinValue" class="text-danger"></span>
|
||||
<p class="form-text text-muted">Example: 5.50 USD</p>
|
||||
</div>
|
||||
<button name="command" type="submit" class="btn btn-success" value="Save">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user