const test = require('node:test'); const assert = require('node:assert'); const L = require('../ladder'); const OP = 'nano_1xug1q5t7nxoj3ywwzokiea9jz8fq8qfgzp8pbyfr3co3e5xgj755uofu8ue'; // the operator's payout address, as in the fixtures const TESTACCT = 'nano_1i3y944esngqw6wb6ia68dotj4yuqctch9kx8ct65twt8ewi4rdcfgax7ggf'; // pursekeeper's own x402 test client, in api/data/own-addresses.json const own = new Set([OP, TESTACCT, 'nano_own']); const N = '1000000000000000000000000000000'; // 1 XNO in raw const raw = x => (BigInt(Math.round(x * 1e6)) * BigInt(N) / 1000000n).toString(); const STAKE = raw(0.16); const ENTRANT = 'nano_entrant'; // synthetic chain builder: ops is a list of [subtype, counterparty, amount]; balances follow const chain = (self, ops) => { let bal = 0n, h = 0; const blocks = ops.map(([subtype, account, x, link]) => { const amt = BigInt(raw(x)); bal = subtype === 'send' ? bal - amt : bal + amt; h++; return { height: h, subtype, account, amount_raw: amt.toString(), balance_raw: bal.toString(), link: link || 'L' + h, hash: 'H' + h, at: new Date(Date.UTC(2026, 8, h)).toISOString() }; }); return { truncated: false, block_count: blocks.length, checked_at: 'x', blocks }; }; const src = (account, ch, receives = [{ at: '2026-09-15T00:00:00.000Z', amount_raw: raw(0.16), hash: 'R' }]) => ({ account, amount_raw: receives.reduce((a, r) => a + BigInt(r.amount_raw), 0n).toString(), first_at: receives[0].at, last_at: receives[receives.length - 1].at, receives, chain: ch }); const other = () => 'other'; test('source held nothing but operator money: the transfers are shown to be operator money, less the dust it got elsewhere', () => { const ch = chain('nano_a', [['receive', OP, 10], ['send', 'nano_x', 1], ['receive', 'nano_y', 0.001], ['send', ENTRANT, 0.6], ['send', ENTRANT, 0.2]]); const r = L.lowerBoundFunding([src('nano_a', ch)], own, other, ENTRANT, STAKE, []); const p = r.per_source[0]; assert.strictEqual(p.balance_before_first_operator_payment_raw, 0n); assert.strictEqual(p.non_operator_received_before_last_transfer_raw, BigInt(raw(0.001))); assert.strictEqual(p.transferred_after_first_operator_payment_chain_raw, BigInt(raw(0.8))); assert.strictEqual(p.operator_money_lower_bound_raw, BigInt(raw(0.799))); assert.deepStrictEqual([r.shown_at_least_stake, r.shown_at_least_stake_other], [true, true]); }); test('source already rich before the operator paid: possible, not shown (lower bound zero) while the upper bound passes', () => { const ch = chain('nano_a', [['receive', 'nano_y', 50], ['receive', OP, 10], ['send', ENTRANT, 0.16]]); const r = L.lowerBoundFunding([src('nano_a', ch)], own, other, ENTRANT, STAKE, []); assert.strictEqual(r.per_source[0].balance_before_first_operator_payment_raw, BigInt(raw(50))); assert.strictEqual(r.per_source[0].operator_money_lower_bound_raw, 0n); assert.strictEqual(r.shown_at_least_stake, false); const u = L.amountFunding([src('nano_a', ch, [{ at: '2026-09-03T00:00:00.000Z', amount_raw: raw(0.16), hash: 'R' }])], own, () => [{ ledger_id: 1, ts: '2026-09-02T00:00:00.000Z', amount_raw: raw(10), kind: 'other' }], STAKE, []); assert.strictEqual(u.bound_at_least_stake, true); // upper bound cannot exclude it; lower bound cannot show it }); test('transfers made before the operator paid do not count; chain order, not clock', () => { const ch = chain('nano_a', [['receive', 'nano_y', 1], ['send', ENTRANT, 0.16], ['receive', OP, 10], ['send', ENTRANT, 0.001]]); const r = L.lowerBoundFunding([src('nano_a', ch)], own, other, ENTRANT, STAKE, []); assert.strictEqual(r.per_source[0].transferred_after_first_operator_payment_chain_raw, BigInt(raw(0.001))); assert.strictEqual(r.per_source[0].operator_money_lower_bound_raw, 0n); // 0.001 - 1 < 0 }); test('a transfer from the source to itself adds no raw and is not a receipt', () => { const ch = chain('nano_a', [['receive', OP, 1], ['send', 'nano_a', 0.5], ['receive', 'nano_a', 0.5], ['send', ENTRANT, 0.16]]); const r = L.lowerBoundFunding([src('nano_a', ch)], own, other, ENTRANT, STAKE, []); assert.strictEqual(r.per_source[0].non_operator_received_before_last_transfer_raw, 0n); assert.strictEqual(r.per_source[0].operator_money_lower_bound_raw, BigInt(raw(0.16))); }); test('excluding ladder returns: a prize the source held before the first purchase counts as non-operator money there', () => { const ch = chain('nano_a', [['receive', OP, 5, 'PRIZE'], ['receive', OP, 0.1, 'BUY'], ['send', ENTRANT, 0.16]]); const kind = link => (link === 'PRIZE' ? 'ladder_payout' : 'other'); const r = L.lowerBoundFunding([src('nano_a', ch)], own, kind, ENTRANT, STAKE, []); const p = r.per_source[0]; assert.strictEqual(p.operator_money_lower_bound_raw, BigInt(raw(0.16))); // any kind: all operator money assert.strictEqual(p.first_other_operator_payment_block.height, 2); assert.strictEqual(p.balance_before_first_other_operator_payment_raw, BigInt(raw(5))); assert.strictEqual(p.operator_money_lower_bound_other_raw, 0n); // the prize could have covered it assert.deepStrictEqual([r.shown_at_least_stake, r.shown_at_least_stake_other], [true, false]); }); test('a ladder refund received inside the window is a receipt in the other reading, not in the any reading', () => { const ch = chain('nano_a', [['receive', OP, 0.2, 'BUY'], ['receive', OP, 0.16, 'REFUND'], ['send', ENTRANT, 0.3]]); const kind = link => (link === 'REFUND' ? 'ladder_refund' : 'other'); const r = L.lowerBoundFunding([src('nano_a', ch)], own, kind, ENTRANT, STAKE, []); assert.strictEqual(r.per_source[0].non_operator_received_before_last_transfer_raw, 0n); assert.strictEqual(r.per_source[0].non_other_operator_received_before_last_transfer_raw, BigInt(raw(0.16))); assert.strictEqual(r.per_source[0].operator_money_lower_bound_raw, BigInt(raw(0.3))); assert.strictEqual(r.per_source[0].operator_money_lower_bound_other_raw, BigInt(raw(0.14))); }); test('no chain, a truncated chain, or a source the operator never paid', () => { const none = L.lowerBoundFunding([src('nano_a', null)], own, other, ENTRANT, STAKE, []); assert.strictEqual(none.per_source[0].operator_money_lower_bound_raw, null); assert.strictEqual(none.shown_at_least_stake, null); const trunc = L.lowerBoundFunding([src('nano_a', { truncated: true, block_count: 3001 })], own, other, ENTRANT, STAKE, []); assert.strictEqual(trunc.per_source[0].chain_truncated, true); assert.strictEqual(trunc.lower_raw, null); const unpaid = L.lowerBoundFunding([src('nano_a', chain('nano_a', [['receive', 'nano_y', 1], ['send', ENTRANT, 0.16]]))], own, other, ENTRANT, STAKE, []); assert.strictEqual(unpaid.per_source[0].first_operator_payment_block, null); assert.strictEqual(unpaid.lower_raw, 0n); assert.strictEqual(unpaid.shown_at_least_stake, false); assert.strictEqual(L.lowerBoundFunding([], own, other, ENTRANT, STAKE, []).shown_at_least_stake, false); assert.strictEqual(L.lowerBoundFunding(null, own, other, ENTRANT, STAKE, []).shown_at_least_stake, null); }); test('an operator-owned source is all operator money: lower equals its transfers; the other figure follows the hop-0 ledger', () => { const r = L.lowerBoundFunding([src('nano_own', null, [{ at: '2026-09-15T00:00:00.000Z', amount_raw: raw(25.64), hash: 'R' }])], own, other, ENTRANT, STAKE, [{ kind: 'ladder_payout', amount_raw: raw(25.48) }, { kind: 'ladder_refund', amount_raw: raw(0.16) }]); assert.strictEqual(r.per_source[0].operator_money_lower_bound_raw, BigInt(raw(25.64))); assert.strictEqual(r.per_source[0].operator_money_lower_bound_other_raw, 0n); assert.deepStrictEqual([r.shown_at_least_stake, r.shown_at_least_stake_other], [true, false]); }); test('round 2 as recorded: nano_16fgno -> nano_165q65 and nano_3uojbn -> nano_3bqpnd, chains read from the node 2026-09-22', () => { const c1 = require('./fixtures/chain-nano_16fgnoqwi.json'), c2 = require('./fixtures/chain-nano_3uojbn47b.json'); const e1 = 'nano_165q65ujhsmsmnn5ejapbem1iieuq4fxzwnshmz7z7zrn9gm3gy8umx998cf', e2 = 'nano_3bqpndmf8wscy7nytddz41o93gca8yaac3aqcagjnin1ofus9aeidqx8k31u'; const r1 = L.lowerBoundFunding([src('nano_16fgnoqwia9haruycrgq38ot71bj8zthpmkutomdm7zb94egb7ucg7uk68cm', c1)], own, other, e1, STAKE, []); const p1 = r1.per_source[0]; assert.strictEqual(p1.first_operator_payment_block.height, 1); assert.strictEqual(p1.balance_before_first_operator_payment_raw, 0n); assert.strictEqual(p1.transferred_after_first_operator_payment_chain_raw, BigInt(raw(0.8))); assert.strictEqual(p1.non_operator_received_before_last_transfer_raw, BigInt(raw(0.001))); assert.strictEqual(L.nanoStr(p1.operator_money_lower_bound_raw), '0.799'); assert.strictEqual(r1.shown_at_least_stake, true); const r2 = L.lowerBoundFunding([src('nano_3uojbn47b5xqcbs4yibbasamn8aeyqxgyi1z8peogwtdn6z3kagjanjpz4ss', c2)], own, other, e2, STAKE, []); const p2 = r2.per_source[0]; assert.strictEqual(p2.transferred_after_first_operator_payment_chain_raw, BigInt(raw(0.49))); assert.strictEqual(p2.balance_before_first_operator_payment_raw, 0n); // receipts from others up to block 49: 0.001 + 0.001 + 0.09715 + 0.001 + 0.01438 + 0 + 0 (the 0.02876 at block 47 is from the operator's own test account and does not count) assert.strictEqual(L.nanoStr(p2.non_operator_received_before_last_transfer_raw), '0.114530040000000000000679477248'); assert.strictEqual(L.nanoStr(p2.operator_money_lower_bound_raw), '0.375469959999999999999320522752'); assert.ok(p2.operator_money_lower_bound_raw >= BigInt(STAKE)); assert.strictEqual(r2.shown_at_least_stake, true); });