Compare commits
10 Commits
feat/nuget
...
v1.3.5
Author | SHA1 | Date | |
---|---|---|---|
0b95da1760 | |||
7aa92e7012 | |||
3bb9e38773 | |||
6597fe7dff | |||
f5677747a4 | |||
74967dc849 | |||
4aef93985d | |||
e5dc4fa854 | |||
1830d5db64 | |||
6f2d29f4e6 |
@ -27,7 +27,7 @@
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NBitcoin" Version="6.0.15" />
|
||||
<PackageReference Include="NBitcoin" Version="6.0.17" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.2.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
@ -33,6 +33,8 @@ namespace BTCPayServer.Client.Models
|
||||
public List<Payment> Payments { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
public string CryptoCode { get; set; }
|
||||
|
||||
public class Payment
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
@ -21,6 +21,7 @@ namespace BTCPayServer.Client.Models
|
||||
public string PullPaymentId { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
|
@ -161,7 +161,7 @@ namespace BTCPayServer.Rating
|
||||
public ExpressionSyntax FindBestCandidate(CurrencyPair p)
|
||||
{
|
||||
var invP = p.Inverse();
|
||||
var candidates = new List<(CurrencyPair Pair, int Prioriy, ExpressionSyntax Expression, bool Inverse)>();
|
||||
var candidates = new List<(CurrencyPair Pair, int Priority, ExpressionSyntax Expression, bool Inverse)>();
|
||||
foreach (var pair in new[]
|
||||
{
|
||||
(Pair: p, Priority: 0, Inverse: false),
|
||||
@ -181,7 +181,7 @@ namespace BTCPayServer.Rating
|
||||
if (candidates.Count == 0)
|
||||
return CreateExpression($"ERR_NO_RULE_MATCH({p})");
|
||||
var best = candidates
|
||||
.OrderBy(c => c.Prioriy)
|
||||
.OrderBy(c => c.Priority)
|
||||
.ThenBy(c => c.Expression.Span.Start)
|
||||
.First();
|
||||
return best.Inverse
|
||||
|
@ -437,6 +437,8 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(payout.Id, payout2.Id);
|
||||
Assert.Equal(destination, payout2.Destination);
|
||||
Assert.Equal(PayoutState.AwaitingApproval, payout.State);
|
||||
Assert.Equal("BTC", payout2.PaymentMethod);
|
||||
Assert.Equal("BTC", payout2.CryptoCode);
|
||||
Assert.Null(payout.PaymentMethodAmount);
|
||||
|
||||
Logs.Tester.LogInformation("Can't overdraft");
|
||||
@ -1186,6 +1188,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(paymentMethods);
|
||||
var paymentMethod = paymentMethods.First();
|
||||
Assert.Equal("BTC", paymentMethod.PaymentMethod);
|
||||
Assert.Equal("BTC", paymentMethod.CryptoCode);
|
||||
Assert.Empty(paymentMethod.Payments);
|
||||
|
||||
|
||||
|
@ -493,7 +493,7 @@ namespace BTCPayServer.Tests
|
||||
var client = new NBitpayClient.Bitpay(new Key(), s.ServerUri);
|
||||
await client.AuthorizeClient(new NBitpayClient.PairingCode(pairingCode));
|
||||
await client.CreateInvoiceAsync(
|
||||
new NBitpayClient.Invoice() { Price = 0.000000012m, Currency = "USD", FullNotifications = true },
|
||||
new NBitpayClient.Invoice() { Price = 1.000000012m, Currency = "USD", FullNotifications = true },
|
||||
NBitpayClient.Facade.Merchant);
|
||||
|
||||
client = new NBitpayClient.Bitpay(new Key(), s.ServerUri);
|
||||
@ -503,7 +503,7 @@ namespace BTCPayServer.Tests
|
||||
s.Driver.FindElement(By.Id("ApprovePairing")).Click();
|
||||
|
||||
await client.CreateInvoiceAsync(
|
||||
new NBitpayClient.Invoice() { Price = 0.000000012m, Currency = "USD", FullNotifications = true },
|
||||
new NBitpayClient.Invoice() { Price = 1.000000012m, Currency = "USD", FullNotifications = true },
|
||||
NBitpayClient.Facade.Merchant);
|
||||
|
||||
s.Driver.Navigate().GoToUrl(s.Link("/api-tokens"));
|
||||
|
@ -3004,15 +3004,31 @@ namespace BTCPayServer.Tests
|
||||
|
||||
[Fact(Timeout = LongRunningTestTimeout)]
|
||||
[Trait("Integration", "Integration")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanCreateStrangeInvoice()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.ActivateLightning();
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.GrantAccess(true);
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
DateTimeOffset expiration = DateTimeOffset.UtcNow + TimeSpan.FromMinutes(21);
|
||||
|
||||
// This should fail, the amount is too low to be above the dust limit of bitcoin
|
||||
var ex = Assert.Throws<BitPayException>(() => user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
Price = 0.000000012m,
|
||||
Currency = "USD",
|
||||
FullNotifications = true,
|
||||
ExpirationTime = expiration
|
||||
}, Facade.Merchant));
|
||||
Assert.Contains("dust threshold", ex.Message);
|
||||
await user.RegisterLightningNodeAsync("BTC");
|
||||
|
||||
var invoice1 = user.BitPay.CreateInvoice(
|
||||
new Invoice()
|
||||
{
|
||||
@ -3021,6 +3037,7 @@ namespace BTCPayServer.Tests
|
||||
FullNotifications = true,
|
||||
ExpirationTime = expiration
|
||||
}, Facade.Merchant);
|
||||
|
||||
Assert.Equal(expiration.ToUnixTimeSeconds(), invoice1.ExpirationTime.ToUnixTimeSeconds());
|
||||
var invoice2 = user.BitPay.CreateInvoice(new Invoice() { Price = 0.000000019m, Currency = "USD" },
|
||||
Facade.Merchant);
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
@ -49,14 +49,14 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
[Authorize(Policy = Policies.CanViewInvoices,
|
||||
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpGet("~/api/v1/stores/{storeId}/invoices")]
|
||||
public async Task<IActionResult> GetInvoices(string storeId, [FromQuery] string[] orderId = null, [FromQuery] string[] status = null,
|
||||
public async Task<IActionResult> GetInvoices(string storeId, [FromQuery] string[]? orderId = null, [FromQuery] string[]? status = null,
|
||||
[FromQuery]
|
||||
[ModelBinder(typeof(ModelBinders.DateTimeOffsetModelBinder))]
|
||||
DateTimeOffset? startDate = null,
|
||||
[FromQuery]
|
||||
[ModelBinder(typeof(ModelBinders.DateTimeOffsetModelBinder))]
|
||||
DateTimeOffset? endDate = null,
|
||||
[FromQuery] string textSearch = null,
|
||||
[FromQuery] string? textSearch = null,
|
||||
[FromQuery] bool includeArchived = false,
|
||||
[FromQuery] int? skip = null,
|
||||
[FromQuery] int? take = null
|
||||
@ -354,6 +354,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
{
|
||||
Activated = details.Activated,
|
||||
PaymentMethod = method.GetId().ToStringNormalized(),
|
||||
CryptoCode = method.GetId().CryptoCode,
|
||||
Destination = details.GetPaymentDestination(),
|
||||
Rate = method.Rate,
|
||||
Due = accounting.DueUncapped.ToDecimal(MoneyUnit.BTC),
|
||||
|
@ -1,3 +1,4 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -98,7 +99,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.Period), $"The period should be positive");
|
||||
}
|
||||
PaymentMethodId[] paymentMethods = null;
|
||||
PaymentMethodId?[]? paymentMethods = null;
|
||||
if (request.PaymentMethods is { } paymentMethodsStr)
|
||||
{
|
||||
paymentMethods = paymentMethodsStr.Select(s =>
|
||||
@ -218,6 +219,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
};
|
||||
model.Destination = blob.Destination;
|
||||
model.PaymentMethod = p.PaymentMethodId;
|
||||
model.CryptoCode = p.GetPaymentMethodId().CryptoCode;
|
||||
return model;
|
||||
}
|
||||
|
||||
@ -245,7 +247,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
if (pp is null)
|
||||
return PullPaymentNotFound();
|
||||
var ppBlob = pp.GetBlob();
|
||||
var destination = await payoutHandler.ParseClaimDestination(paymentMethodId,request.Destination, true);
|
||||
var destination = await payoutHandler.ParseClaimDestination(paymentMethodId, request!.Destination, true);
|
||||
if (destination.destination is null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(request.Destination), destination.error??"The destination is invalid for the payment specified");
|
||||
@ -338,7 +340,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
var payout = await ctx.Payouts.GetPayout(payoutId, storeId, true, true);
|
||||
if (payout is null)
|
||||
return PayoutNotFound();
|
||||
RateResult rateResult = null;
|
||||
RateResult? rateResult = null;
|
||||
try
|
||||
{
|
||||
rateResult = await _pullPaymentService.GetRate(payout, approvePayoutRequest?.RateRule, cancellationToken);
|
||||
@ -357,7 +359,7 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
var result = await _pullPaymentService.Approve(new PullPaymentHostedService.PayoutApproval()
|
||||
{
|
||||
PayoutId = payoutId,
|
||||
Revision = revision.Value,
|
||||
Revision = revision!.Value,
|
||||
Rate = rateResult.BidAsk.Ask
|
||||
});
|
||||
var errorMessage = PullPaymentHostedService.PayoutApproval.GetErrorMessage(result);
|
||||
|
@ -516,10 +516,12 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
paymentMethodId = enabledPaymentIds.FirstOrDefault(e => e.CryptoCode == "BTC" && e.PaymentType == PaymentTypes.BTCLike) ??
|
||||
enabledPaymentIds.FirstOrDefault(e => e.CryptoCode == "BTC" && e.PaymentType == PaymentTypes.LightningLike) ??
|
||||
enabledPaymentIds.First();
|
||||
enabledPaymentIds.FirstOrDefault();
|
||||
}
|
||||
isDefaultPaymentId = true;
|
||||
}
|
||||
if (paymentMethodId is null)
|
||||
return null;
|
||||
BTCPayNetworkBase network = _NetworkProvider.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode);
|
||||
if (network is null || !invoice.Support(paymentMethodId))
|
||||
{
|
||||
@ -529,7 +531,9 @@ namespace BTCPayServer.Controllers
|
||||
.GetPaymentMethods()
|
||||
.FirstOrDefault(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode);
|
||||
if (paymentMethodTemp == null)
|
||||
paymentMethodTemp = invoice.GetPaymentMethods().First();
|
||||
paymentMethodTemp = invoice.GetPaymentMethods().FirstOrDefault();
|
||||
if (paymentMethodTemp is null)
|
||||
return null;
|
||||
network = paymentMethodTemp.Network;
|
||||
paymentMethodId = paymentMethodTemp.GetId();
|
||||
}
|
||||
|
@ -65,14 +65,23 @@ namespace BTCPayServer.Controllers
|
||||
if (CurrentStore is null)
|
||||
return NotFound();
|
||||
|
||||
var paymentMethodOptions = await _payoutHandlers.GetSupportedPaymentMethods(CurrentStore);
|
||||
var paymentMethods = await _payoutHandlers.GetSupportedPaymentMethods(CurrentStore);
|
||||
if (!paymentMethods.Any())
|
||||
{
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Message = "You must enable at least one payment method before creating a pull payment.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction("PaymentMethods", "Stores", new { storeId });
|
||||
}
|
||||
return View(new NewPullPaymentModel
|
||||
{
|
||||
Name = "",
|
||||
Currency = "BTC",
|
||||
CustomCSSLink = "",
|
||||
EmbeddedCSS = "",
|
||||
PaymentMethodItems = paymentMethodOptions.Select(id => new SelectListItem(id.ToPrettyString(), id.ToString(), true))
|
||||
PaymentMethodItems = paymentMethods.Select(id => new SelectListItem(id.ToPrettyString(), id.ToString(), true))
|
||||
});
|
||||
}
|
||||
|
||||
@ -406,6 +415,16 @@ namespace BTCPayServer.Controllers
|
||||
int skip = 0, int count = 50)
|
||||
{
|
||||
var paymentMethods = await _payoutHandlers.GetSupportedPaymentMethods(HttpContext.GetStoreData());
|
||||
if (!paymentMethods.Any())
|
||||
{
|
||||
TempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Message = "You must enable at least one payment method before creating a payout.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction("PaymentMethods", "Stores", new { storeId });
|
||||
}
|
||||
|
||||
var vm = this.ParseListQuery(new PayoutsModel
|
||||
{
|
||||
PaymentMethods = paymentMethods,
|
||||
|
@ -136,7 +136,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
|
||||
claimDestination is IBitcoinLikeClaimDestination bitcoinLikeClaimDestination)
|
||||
{
|
||||
txout.ScriptPubKey = bitcoinLikeClaimDestination.Address.ScriptPubKey;
|
||||
return Task.FromResult(txout.GetDustThreshold(new FeeRate(1.0m)).ToDecimal(MoneyUnit.BTC));
|
||||
return Task.FromResult(txout.GetDustThreshold().ToDecimal(MoneyUnit.BTC));
|
||||
}
|
||||
|
||||
return Task.FromResult(0m);
|
||||
|
@ -190,6 +190,15 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
}
|
||||
|
||||
var reserved = await prepare.ReserveAddress;
|
||||
if (paymentMethod.ParentEntity.Type != InvoiceType.TopUp)
|
||||
{
|
||||
var txOut = network.NBitcoinNetwork.Consensus.ConsensusFactory.CreateTxOut();
|
||||
txOut.ScriptPubKey = reserved.Address.ScriptPubKey;
|
||||
var dust = txOut.GetDustThreshold();
|
||||
var amount = paymentMethod.Calculate().Due;
|
||||
if (amount < dust)
|
||||
throw new PaymentMethodUnavailableException("Amount below the dust threshold. For amounts of this size, it is recommended to enable an off-chain (Lightning) payment method");
|
||||
}
|
||||
onchainMethod.DepositAddress = reserved.Address.ToString();
|
||||
onchainMethod.KeyPath = reserved.KeyPath;
|
||||
onchainMethod.PayjoinEnabled = blob.PayJoinEnabled &&
|
||||
|
@ -424,7 +424,7 @@ namespace BTCPayServer.Payments.PayJoin
|
||||
{
|
||||
var outputContribution = Money.Min(additionalFee, -due);
|
||||
outputContribution = Money.Min(outputContribution,
|
||||
newTx.Outputs[i].Value - newTx.Outputs[i].GetDustThreshold(minRelayTxFee));
|
||||
newTx.Outputs[i].Value - newTx.Outputs[i].GetDustThreshold());
|
||||
newTx.Outputs[i].Value -= outputContribution;
|
||||
additionalFee -= outputContribution;
|
||||
due += outputContribution;
|
||||
@ -437,7 +437,7 @@ namespace BTCPayServer.Payments.PayJoin
|
||||
{
|
||||
var outputContribution = Money.Min(additionalFee, feeOutput.Value);
|
||||
outputContribution = Money.Min(outputContribution,
|
||||
feeOutput.Value - feeOutput.GetDustThreshold(minRelayTxFee));
|
||||
feeOutput.Value - feeOutput.GetDustThreshold());
|
||||
outputContribution = Money.Min(outputContribution, allowedSenderFeeContribution);
|
||||
feeOutput.Value -= outputContribution;
|
||||
additionalFee -= outputContribution;
|
||||
|
@ -65,7 +65,7 @@
|
||||
{
|
||||
<span v-if="srvModel.targetAmount" class="mt-3" id="crowdfund-header-target">
|
||||
<h3 class="d-inline-block">
|
||||
<span class="badge bg-info px-3" v-text="`${new Intl.NumberFormat().format(srvModel.targetAmount)} ${targetCurrency}`">@Math.Round(Model.TargetAmount.GetValueOrDefault(0)) @Model.TargetCurrency</span>
|
||||
<span class="badge bg-info px-3" v-text="`${targetAmount} ${targetCurrency}`">@Math.Round(Model.TargetAmount.GetValueOrDefault(0)) @Model.TargetCurrency</span>
|
||||
</h3>
|
||||
@if (Model.ResetEveryAmount > 0 && !Model.NeverReset)
|
||||
{
|
||||
@ -123,7 +123,7 @@
|
||||
<div class="card-body">
|
||||
<div class="row py-2 text-center crowdfund-stats">
|
||||
<div class="col-sm border-end p-3 text-center" id="crowdfund-body-raised-amount">
|
||||
<h3 v-text="`${new Intl.NumberFormat().format(raisedAmount)} ${targetCurrency}`">@Math.Round(Model.Info.CurrentAmount + Model.Info.CurrentPendingAmount) @Model.TargetCurrency</h3>
|
||||
<h3 v-text="`${raisedAmount} ${targetCurrency}`">@Math.Round(Model.Info.CurrentAmount + Model.Info.CurrentPendingAmount, Model.CurrencyData.Divisibility) @Model.TargetCurrency</h3>
|
||||
<h5 class="text-muted fst-italic mb-0">Raised</h5>
|
||||
<b-tooltip target="crowdfund-body-raised-amount" v-if="paymentStats && paymentStats.length > 0" class="only-for-js">
|
||||
<ul class="p-0 text-uppercase">
|
||||
@ -287,8 +287,8 @@
|
||||
|
||||
<template id="perks-template">
|
||||
<div class="perks-container">
|
||||
<perk v-if="!perks || perks.length ===0"
|
||||
:perk="{title: 'Donate Custom Amount', price: { type: 0, value: null}}"
|
||||
<perk v-if="!perks || perks.length === 0"
|
||||
:perk="{title: 'Donate Custom Amount', price: { type: 0, value: null}}"
|
||||
:target-currency="targetCurrency"
|
||||
:active="active"
|
||||
:loading="loading"
|
||||
@ -324,10 +324,10 @@
|
||||
<img v-if="perk.image && perk.image != 'null'" class="card-img-top" :src="perk.image" />
|
||||
<div class="card-body">
|
||||
<div class="card-title d-flex justify-content-between">
|
||||
<span class="h5">{{perk.title? perk.title : perk.id}}</span>
|
||||
<span class="h5">{{perk.title ? perk.title : perk.id}}</span>
|
||||
<span class="text-muted">
|
||||
<template v-if="perk.price && perk.price.value">
|
||||
{{new Intl.NumberFormat().format(perk.price.value.noExponents())}}
|
||||
{{formatAmount(perk.price.value.noExponents(), srvModel.currencyData.divisibility)}}
|
||||
{{targetCurrency}}
|
||||
<template v-if="perk.price.type == 1">or more</template>
|
||||
</template>
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model ListTransactionsViewModel
|
||||
@model ListTransactionsViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData.SetActivePageAndTitle(WalletsNavPages.Transactions, $"{Model.CryptoCode} Transactions", Context.GetStoreData().StoreName);
|
||||
@ -35,7 +35,6 @@
|
||||
|
||||
.badge-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,6 @@ document.addEventListener("DOMContentLoaded",function (ev) {
|
||||
this.amount = this.perk.price.type === 0? null : (amount || 0).noExponents();
|
||||
this.expanded = false;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
mounted: function () {
|
||||
this.setAmount(this.perk.price.value);
|
||||
@ -63,7 +61,6 @@ document.addEventListener("DOMContentLoaded",function (ev) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
app = new Vue({
|
||||
@ -82,14 +79,17 @@ document.addEventListener("DOMContentLoaded",function (ev) {
|
||||
active: true,
|
||||
animation: true,
|
||||
sound: true,
|
||||
lastUpdated:"",
|
||||
lastUpdated: "",
|
||||
loading: false,
|
||||
timeoutState: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
raisedAmount: function(){
|
||||
return parseFloat(this.srvModel.info.currentAmount + this.srvModel.info.currentPendingAmount ).toFixed(this.srvModel.currencyData.divisibility) ;
|
||||
return this.formatAmount(this.srvModel.info.currentAmount + this.srvModel.info.currentPendingAmount);
|
||||
},
|
||||
targetAmount: function(){
|
||||
return this.formatAmount(this.srvModel.targetAmount);
|
||||
},
|
||||
percentageRaisedAmount: function(){
|
||||
return parseFloat(this.srvModel.info.progressPercentage + this.srvModel.info.pendingProgressPercentage ).toFixed(2);
|
||||
@ -203,6 +203,9 @@ document.addEventListener("DOMContentLoaded",function (ev) {
|
||||
if(this.timeoutState){
|
||||
clearTimeout(this.timeoutState);
|
||||
}
|
||||
},
|
||||
formatAmount: function(amount) {
|
||||
return formatAmount(amount, this.srvModel.currencyData.divisibility)
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
@ -315,3 +318,18 @@ document.addEventListener("DOMContentLoaded",function (ev) {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Formats input string as a number according to browser locale
|
||||
* with correctly displayed fraction amount (e.g. 0.012345 for BTC instead of just 0.0123)
|
||||
*
|
||||
* @param {number | string} amount Amount to format
|
||||
* @param {number} divisibility Currency divisibility (e.g., 8 for BTC)
|
||||
* @returns String formatted as a number according to current browser locale and correct fraction amount
|
||||
*/
|
||||
function formatAmount(amount, divisibility) {
|
||||
var parsedAmount = parseFloat(amount).toFixed(divisibility);
|
||||
var [wholeAmount, fractionAmount] = parsedAmount.split('.');
|
||||
var formattedWholeAmount = new Intl.NumberFormat().format(parseInt(wholeAmount, 10));
|
||||
|
||||
return formattedWholeAmount + (fractionAmount ? '.' + fractionAmount : '');
|
||||
}
|
||||
|
@ -1152,7 +1152,11 @@
|
||||
"properties": {
|
||||
"paymentMethod": {
|
||||
"type": "string",
|
||||
"description": "The payment method"
|
||||
"description": "Payment method available for the invoice (e.g., \"BTC\" or \"BTC-LightningNetwork\" or \"BTC-LNURLPAY\")"
|
||||
},
|
||||
"cryptoCode": {
|
||||
"type": "string",
|
||||
"description": "Crypto code of the payment method (e.g., \"BTC\" or \"LTC\")"
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
|
@ -313,6 +313,46 @@
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/pull-payments/{pullPaymentId}/payouts/{payoutId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pullPaymentId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The ID of the pull payment",
|
||||
"schema": { "type": "string" }
|
||||
},
|
||||
{
|
||||
"name": "payoutId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The ID of the pull payment payout",
|
||||
"schema": { "type": "string" }
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"summary": "Get Payout",
|
||||
"operationId": "PullPayments_GetPayout",
|
||||
"description": "Get payout",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A specific payout of a pull payment",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PayoutData"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Pull payment payout not found"
|
||||
}
|
||||
},
|
||||
"tags": [ "Pull payments (Public)", "Pull payments payout (Public)" ],
|
||||
"security": []
|
||||
}
|
||||
},
|
||||
"/api/v1/stores/{storeId}/payouts/{payoutId}": {
|
||||
"parameters": [
|
||||
{
|
||||
@ -554,7 +594,12 @@
|
||||
"paymentMethod": {
|
||||
"type": "string",
|
||||
"example": "BTC",
|
||||
"description": "The payment method of the payout"
|
||||
"description": "The payment method of the payout (e.g., \"BTC\" or \"BTC_LightningLike\""
|
||||
},
|
||||
"cryptoCode": {
|
||||
"type": "string",
|
||||
"example": "BTC",
|
||||
"description": "Crypto code of the payment method of the payout (e.g., \"BTC\" or \"LTC\")"
|
||||
},
|
||||
"paymentMethodAmount": {
|
||||
"type": "string",
|
||||
|
@ -65,7 +65,7 @@
|
||||
"description": "Whether the payment method is enabled"
|
||||
},
|
||||
"cryptoCode": {
|
||||
"type": "boolean",
|
||||
"type": "string",
|
||||
"description": "The currency code of the payment method"
|
||||
},
|
||||
"data": {
|
||||
|
@ -625,7 +625,7 @@
|
||||
"type": {
|
||||
"type": "string",
|
||||
"nullable": false,
|
||||
"description": "The type of this event, current available are `InvoiceCreated`, `InvoiceReceivedPayment`, `InvoicePaidInFull`, `InvoiceExpired`, `InvoiceSettled`, and `InvoiceInvalid`."
|
||||
"description": "The type of this event, current available are `InvoiceCreated`, `InvoiceReceivedPayment`, `InvoiceProcessing`, `InvoiceExpired`, `InvoiceSettled`, `InvoiceInvalid`, and `InvoicePaymentSettled`."
|
||||
},
|
||||
"timestamp": {
|
||||
"description": "The timestamp when this delivery has been created",
|
||||
@ -899,9 +899,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"InvoicePaidInFull": {
|
||||
"InvoiceProcessing": {
|
||||
"post": {
|
||||
"summary": "InvoicePaidInFull",
|
||||
"summary": "InvoiceProcessing",
|
||||
"description": "Triggers when an invoice is fully paid, but doesn't have the required amount of confirmations on the blockchain yet according to your store's settings.",
|
||||
"parameters": [
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.3.4</Version>
|
||||
<Version>1.3.5</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
16
Changelog.md
16
Changelog.md
@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## 1.3.5
|
||||
|
||||
### Bug fixes:
|
||||
|
||||
* Fix: Checkout page of for invoices of 0 amount shouldn't crash, but 404 @NicolasDorier
|
||||
* Swagger doc: Fix type of property cryptoCode (#3088) @ndeet
|
||||
* Fix bug with fraction amount display in crowdfund app (#3098) @bolatovumar
|
||||
* Swagger doc: Update Swagger docs for webhook event types (#3104) @bolatovumar
|
||||
* Payout/pull payment page would crash if no payment method are set on the store @satwo
|
||||
|
||||
### Improvements:
|
||||
|
||||
* Add crypto code for invoice and pull payment payout API response (#3099) @bolatovumar
|
||||
* Prevent creation of on-chain invoices below the dust limit (#3082) @satwo
|
||||
|
||||
|
||||
## 1.3.4
|
||||
|
||||
### Bug fixes:
|
||||
|
Reference in New Issue
Block a user