Files
AtreidesAssetsFree/shared/units.js
T
2026-10-29 11:57:29 +01:00

118 lines
4.0 KiB
JavaScript

// Generated, do not edit. sha256:20efe63e56f8374f20930043f99fa07bae78df1e6fc48a984d3f6364d25853bf
import { CONFIG } from './config.js';
import { fail } from './app-error.js';
const M = CONFIG.METALS;
export const isMetal = asset => !!asset && asset.kind === 'metal';
export function metalFactor(code) {
const f = M.UNITS[code];
if (!f) throw new Error(`Unknown metal unit: '${code}'.`);
return f;
}
export function metalPrimary(asset) {
return asset.displayUnit === 'subunit' && asset.subunit ? asset.subunit : asset.unit;
}
export function metalSecondary(asset) {
return asset.displayUnit === 'subunit' && asset.subunit ? asset.unit : asset.subunit;
}
export function toBaseByFactor(value, code) {
const n = Number(value);
if (!Number.isFinite(n)) fail('common.invalidAmount', null, 'Invalid amount.');
return Math.round(n * metalFactor(code) * Math.pow(10, M.BASE_DECIMALS));
}
export function fromBaseByFactor(amount, code) {
return (Number(amount) / Math.pow(10, M.BASE_DECIMALS)) / metalFactor(code);
}
export function mainToSub(main, decimals) {
return Math.round(Number(main) * Math.pow(10, decimals || 0));
}
export function subToMain(sub, decimals) {
const d = decimals || 0;
return Number((Number(sub) / Math.pow(10, d)).toFixed(d));
}
export function toSubunit(value, asset) {
if (isMetal(asset)) return toBaseByFactor(value, metalPrimary(asset));
const n = Number(value);
if (!Number.isFinite(n)) fail('common.invalidAmount', null, 'Invalid amount.');
const dec = asset.decimals ?? 0;
return asset.displayUnit === 'subunit' ? Math.round(n) : mainToSub(n, dec);
}
export function fromSubunit(amount, asset) {
if (isMetal(asset)) return fromBaseByFactor(amount, metalPrimary(asset));
const dec = asset.decimals ?? 0;
if (asset.displayUnit === 'subunit') return amount;
return subToMain(amount, dec);
}
export function unitToSubunit(value, asset) {
if (isMetal(asset)) return toBaseByFactor(value, asset.unit);
const n = Number(value);
if (!Number.isFinite(n)) fail('common.invalidAmount', null, 'Invalid amount.');
return mainToSub(n, asset.decimals ?? 0);
}
export function priceToBase(price, asset) {
const n = Number(price);
return isMetal(asset) ? n / metalFactor(metalPrimary(asset)) : n;
}
export function priceFromBase(stored, asset) {
const n = Number(stored);
return isMetal(asset) ? n * metalFactor(metalPrimary(asset)) : n;
}
export function unitPriceToBase(price, asset) {
const n = Number(price);
if (!Number.isFinite(n)) throw new Error('Invalid price.');
return isMetal(asset) ? n / metalFactor(asset.unit) : n;
}
function getal(v) {
if (v === null || v === undefined) return null;
if (typeof v === 'string' && v.trim() === '') return null;
const n = Number(v);
return Number.isFinite(n) ? n : null;
}
function feeSigned(fee, type) {
const f = getal(fee) ?? 0;
return type === 'sell' ? -f : f;
}
export function totalFromPrice(amountBase, decimals, priceBase, fee = 0, type = 'buy') {
const a = getal(amountBase), p = getal(priceBase);
if (a === null || p === null) return null;
return (a / Math.pow(10, decimals ?? 0)) * p + feeSigned(fee, type);
}
export function priceFromTotal(total, amountBase, decimals, fee = 0, type = 'buy') {
const tot = getal(total), a = getal(amountBase);
if (tot === null || a === null) return null;
const eenheden = a / Math.pow(10, decimals ?? 0);
const netto = tot - feeSigned(fee, type);
if (netto < 0) return null;
return eenheden > 0 ? netto / eenheden : null;
}
export function amountFromTotal(total, priceBase, decimals, fee = 0, type = 'buy') {
const tot = getal(total), p = getal(priceBase);
if (tot === null || p === null || p <= 0) return null;
const netto = tot - feeSigned(fee, type);
if (netto < 0) return null;
return (netto / p) * Math.pow(10, decimals ?? 0);
}
export function priceUnitLabel(asset) {
return isMetal(asset) ? metalPrimary(asset) : asset?.unit;
}
export function hasSubunit(asset) {
return !!(asset && typeof asset.subunit === 'string' && asset.subunit.trim() !== '');
}