nx_fx_lib.nx source
↩ module page · 99 lines · 4663 B
1// nx_fx_lib.nx -- F984: EXACT MULTI-CURRENCY on the sovereign ledger.
2//
3// Every incumbent FX path loses fractions of a cent to rounding and buries it. The sovereign property
4// here is that a conversion LOSES NO VALUE: the truncated remainder is RETURNED and accounted, never
5// silently dropped, so a converted amount can be reconstructed EXACTLY. Money is neither created nor
6// destroyed by crossing a currency boundary -- the same invariant the ledger enforces within one
7// currency, extended across two.
8//
9// A rate is a RATIONAL num/den (integer, exact) -- never a float, because a float rate drifts and an
10// auditor cannot reproduce it. A rate carries PROVENANCE (source + the pair it prices): a conversion
11// can cite exactly which rate, from which source, produced its number. No provenance, no conversion is
12// the honest posture, though the raw fx_convert is available for pure arithmetic.
13//
14// FAIL-CLOSED: a zero or negative denominator is REFUSED (return -1, remainder 0) -- a divide-by-zero
15// rate is a data error, not a silent NaN.
16//
17// SCALE ENVELOPE (declared): fx_convert computes amount*num before dividing, so amount*num must fit i64
18// (~9.2e18). For cents and realistic rates this is billions of dollars of headroom; a 128-bit widening
19// mul is the rung if a book ever needs trillions-of-minor-units single transactions. Declared, not hidden.
20// DRY: composes nx_matter_lib (reg_put/reg_get/mt_field/canon_encode) for rate storage. license_tier: ORIGINAL LIB.
21
22import "nx_matter_lib.nx"
23const FX_MAGIC_1024: i64 = 1024
24
25const FX_BAD_RATE: i64 = 0 - 1
26
27func fx_atoi(s: *u8) -> i64 {
28 var v: i64 = 0
29 var i: i64 = 0
30 var neg: i64 = 0
31 if s[0] == (45 as u8) { neg = 1; i = 1 }
32 while s[i] != (0 as u8) {
33 if s[i] >= 48 as u8 { if s[i] <= 57 as u8 { v = v * 10 + (s[i] - 48) } }
34 i = i + 1
35 }
36 if neg == 1 { return 0 - v }
37 return v
38}
39
40// ★EXACT CONVERSION. amount (minor units, currency A) -> minor units, currency B, at rate num/den.
41// Writes the truncated remainder (in A*num units) to rem[0]. Returns -1 (FX_BAD_RATE) if den <= 0.
42// The remainder is what makes this lossless: amount_b*den + rem == amount*num, always.
43func fx_convert(amount: i64, rate_num: i64, rate_den: i64, rem: *i64) -> i64 {
44 if rate_den <= 0 { rem[0] = 0; return FX_BAD_RATE }
45 let prod: i64 = amount * rate_num
46 rem[0] = prod % rate_den
47 return prod / rate_den
48}
49
50// ★RECONSTRUCT the exact source amount from a converted amount + its accounted remainder.
51// Proves value was conserved: fx_reconstruct(fx_convert(a)) == a. Returns -1 on a bad rate.
52func fx_reconstruct(amount_b: i64, rem: i64, rate_num: i64, rate_den: i64) -> i64 {
53 if rate_num <= 0 { return FX_BAD_RATE }
54 return (amount_b * rate_den + rem) / rate_num
55}
56
57// store a rate for a currency pair with its source (provenance). pair_id e.g. "USD-EUR".
58func fx_rate_put(prefix: *u8, pair_id: *u8, rate_num: i64, rate_den: i64, source: *u8) -> i64 {
59 let nb: *u8 = sys_mmap(32)
60 var no: i64 = mt_catn(nb, 0, rate_num)
61 nb[no] = 0 as u8
62 let db: *u8 = sys_mmap(32)
63 var doo: i64 = mt_catn(db, 0, rate_den)
64 db[doo] = 0 as u8
65 let k: *i64 = sys_mmap(8 * 3) as *i64
66 let v: *i64 = sys_mmap(8 * 3) as *i64
67 k[0] = ("num" as *u8) as i64
68 v[0] = nb as i64
69 k[1] = ("den" as *u8) as i64
70 v[1] = db as i64
71 k[2] = ("source" as *u8) as i64
72 v[2] = source as i64
73 let rec: *u8 = sys_mmap(FX_MAGIC_1024)
74 let rl: i64 = canon_encode(k, v, 3, rec)
75 return reg_put(prefix, "fxr:" as *u8, "fxr:__idx__" as *u8, pair_id, rec, rl)
76}
77
78// load a stored rate into num[0]/den[0]; returns 1 if found, 0 if the pair is unpriced.
79func fx_rate_get(prefix: *u8, pair_id: *u8, num: *i64, den: *i64) -> i64 {
80 let po: *i64 = sys_mmap(16) as *i64
81 let lo: *i64 = sys_mmap(16) as *i64
82 if reg_get(prefix, "fxr:" as *u8, pair_id, po, lo) != 1 { return 0 }
83 let nf: *u8 = sys_mmap(32)
84 let df: *u8 = sys_mmap(32)
85 mt_field(po[0] as *u8, lo[0], "num" as *u8, 3, nf)
86 mt_field(po[0] as *u8, lo[0], "den" as *u8, 3, df)
87 num[0] = fx_atoi(nf)
88 den[0] = fx_atoi(df)
89 return 1
90}
91
92// ★CONVERT USING A STORED, SOURCED RATE (provenance-gated). Returns the converted minor units and
93// writes the remainder; returns -1 if the pair has no stored rate (no conversion without a cited rate).
94func fx_convert_priced(prefix: *u8, pair_id: *u8, amount: i64, rem: *i64) -> i64 {
95 let num: *i64 = sys_mmap(16) as *i64
96 let den: *i64 = sys_mmap(16) as *i64
97 if fx_rate_get(prefix, pair_id, num, den) != 1 { rem[0] = 0; return FX_BAD_RATE }
98 return fx_convert(amount, num[0], den[0], rem)
99}