Fix zap fee parsing for split calculations

This commit is contained in:
thePR0M3TH3AN committed 2025-10-05 22:03:07 -04:00
1 parent c0ffde6462
commit b773e1ec21
4 files changed
+114 -69

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
// js/payments/platformFee.js
import { PLATFORM_FEE_PERCENT } from "../config.js";
export function parsePercentValue(value) {
if (typeof value === "number") {
return Number.isFinite(value) ? value : NaN;
}
if (typeof value === "bigint") {
return Number(value);
}
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) {
return NaN;
}
if (trimmed.includes("/")) {
const [firstRaw, secondRaw] = trimmed.split("/").map((part) => part.trim());
if (firstRaw && secondRaw) {
const first = Number(firstRaw);
const second = Number(secondRaw);
if (Number.isFinite(first) && Number.isFinite(second) && first >= 0 && second >= 0) {
const total = first + second;
if (total > 0) {
return (second / total) * 100;
}
}
}
}
const percentStripped = trimmed.endsWith("%") ? trimmed.slice(0, -1).trim() : trimmed;
const directNumeric = Number(percentStripped);
if (Number.isFinite(directNumeric)) {
return directNumeric;
}
const match = percentStripped.match(/-?\d+(?:\.\d+)?/);
if (match) {
const fallback = Number(match[0]);
return Number.isFinite(fallback) ? fallback : NaN;
}
return NaN;
}
return Number.isFinite(value) ? Number(value) : NaN;
}
export function clampPercent(value) {
const numeric = parsePercentValue(value);
if (!Number.isFinite(numeric)) {
return 0;
}
return Math.min(100, Math.max(0, numeric));
}
export function getDefaultPlatformFeePercent() {
const parsed = parsePercentValue(PLATFORM_FEE_PERCENT);
if (!Number.isFinite(parsed)) {
return 0;
}
return clampPercent(parsed);
}
export function resolvePlatformFeePercent(overrideValue) {
const parsedOverride = parsePercentValue(overrideValue);
if (Number.isFinite(parsedOverride)) {
return clampPercent(parsedOverride);
}
return getDefaultPlatformFeePercent();
}
+4 -6
View File
@@ -1,4 +1,4 @@
import { PLATFORM_FEE_PERCENT } from "../config.js";
import { resolvePlatformFeePercent } from "./platformFee.js";
import {
resolveLightningAddress as defaultResolveLightningAddress,
fetchPayServiceData as defaultFetchPayServiceData,
@@ -112,11 +112,9 @@ export async function fetchLightningMetadata(
export function calculateZapShares(amount, overrideFee = null) {
const numericAmount = Math.max(0, Math.round(Number(amount) || 0));
const percentSource =
typeof overrideFee === "number" && Number.isFinite(overrideFee)
? overrideFee
: PLATFORM_FEE_PERCENT;
const feePercent = Math.min(100, Math.max(0, Math.round(percentSource)));
const feePercent = resolvePlatformFeePercent(
typeof overrideFee === "undefined" ? null : overrideFee
);
const platformShare = Math.floor((numericAmount * feePercent) / 100);
const creatorShare = numericAmount - platformShare;
return {
+7 -63
View File
@@ -1,6 +1,6 @@
// js/payments/zapSplit.js
import { PLATFORM_FEE_PERCENT, ADMIN_SUPER_NPUB } from "../config.js";
import { ADMIN_SUPER_NPUB } from "../config.js";
import {
resolveLightningAddress,
fetchPayServiceData,
@@ -9,6 +9,11 @@ import {
} from "./lnurl.js";
import { ensureWallet, sendPayment } from "./nwcClient.js";
import { getPlatformLightningAddress } from "./platformAddress.js";
import {
clampPercent,
parsePercentValue,
resolvePlatformFeePercent,
} from "./platformFee.js";
const HEX64_REGEX = /^[0-9a-f]{64}$/i;
const ZAP_KIND = 9734;
@@ -23,69 +28,8 @@ const DEFAULT_DEPS = Object.freeze({
platformAddress: Object.freeze({ getPlatformLightningAddress }),
});
function parsePercentValue(value) {
if (typeof value === "number") {
return Number.isFinite(value) ? value : NaN;
}
if (typeof value === "bigint") {
return Number(value);
}
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) {
return NaN;
}
if (trimmed.includes("/")) {
const [firstRaw, secondRaw] = trimmed.split("/").map((part) => part.trim());
if (firstRaw && secondRaw) {
const first = Number(firstRaw);
const second = Number(secondRaw);
if (Number.isFinite(first) && Number.isFinite(second) && first >= 0 && second >= 0) {
const total = first + second;
if (total > 0) {
return (second / total) * 100;
}
}
}
}
const percentStripped = trimmed.endsWith("%")
? trimmed.slice(0, -1).trim()
: trimmed;
const directNumeric = Number(percentStripped);
if (Number.isFinite(directNumeric)) {
return directNumeric;
}
const match = percentStripped.match(/-?\d+(?:\.\d+)?/);
if (match) {
const fallback = Number(match[0]);
return Number.isFinite(fallback) ? fallback : NaN;
}
return NaN;
}
return Number.isFinite(value) ? Number(value) : NaN;
}
function getOverridePlatformFee() {
const override = parsePercentValue(globalThis?.__BITVID_PLATFORM_FEE_OVERRIDE__);
if (Number.isFinite(override)) {
return override;
}
return PLATFORM_FEE_PERCENT;
}
function clampPercent(value) {
const numeric = parsePercentValue(value);
if (!Number.isFinite(numeric)) {
return 0;
}
return Math.min(100, Math.max(0, numeric));
return resolvePlatformFeePercent(globalThis?.__BITVID_PLATFORM_FEE_OVERRIDE__);
}
function sanitizeAmount(amount) {
+29
View File
@@ -0,0 +1,29 @@
import assert from "node:assert/strict";
const sharedStateModule = await import("../js/payments/zapSharedState.js");
const feeModule = await import("../js/payments/platformFee.js");
const { calculateZapShares } = sharedStateModule;
const { resolvePlatformFeePercent } = feeModule;
(function testCalculateZapSharesSupportsRatioOverride() {
const result = calculateZapShares(35, "70/30");
assert.equal(result.total, 35);
assert.equal(result.platformShare, 10);
assert.equal(result.creatorShare, 25);
assert.equal(result.feePercent, 30);
})();
(function testCalculateZapSharesHandlesPercentStrings() {
const result = calculateZapShares(200, "30% ");
assert.equal(result.platformShare, 60);
assert.equal(result.creatorShare, 140);
assert.equal(result.feePercent, 30);
})();
(function testResolvePlatformFeePercentFallsBackToDefault() {
const percent = resolvePlatformFeePercent("not-a-number");
assert.equal(percent, 0);
})();
console.log("zap-shared-state tests passed");