code wiki / (root) / nx_fx_lib.nx

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}