import { test } from 'node:test'; import assert from 'node:assert/strict'; import { vestedAt, statusOf, validateSchedule, CHAIN } from '../src/vesting.js'; const s={total:'1001',released:'0',start:1000,cliff:1250,end:2000}; test('linear math: before start, before cliff, cliff catch-up, end, rounding',()=>{ assert.equal(vestedAt(s,999),0n);assert.equal(vestedAt(s,1249),0n);assert.equal(vestedAt(s,1250),250n);assert.equal(vestedAt(s,1500),500n);assert.equal(vestedAt(s,2000),1001n);assert.equal(vestedAt(s,3000),1001n); }); test('big integers never pass through floating point',()=>{const large={...s,total:'1000000000000000000000000001'};assert.equal(vestedAt(large,1500),500000000000000000000000000n);}); test('status separates locked, vesting, fully claimed',()=>{assert.equal(statusOf(s,1100),'locked');assert.equal(statusOf(s,1300),'active');assert.equal(statusOf({...s,released:'1001'},3000),'complete');}); const input={token:'0x2222222222222222222222222222222222222222',beneficiary:'0x1111111111111111111111111111111111111111',amount:'1.25',start:2000,cliff:2500,end:3000}; test('validation uses token decimals and preserves full amount',()=>assert.equal(validateSchedule(input,6,1000).total,'1250000')); test('invalid addresses, amounts, times and precision are rejected',()=>{ for(const bad of [{beneficiary:'0x0'},{token:'0x0000000000000000000000000000000000000000'},{amount:'-1'},{amount:'0'},{amount:'1e3'},{amount:'1.1234567'},{start:1000},{cliff:1999},{cliff:3001},{end:2000},{start:NaN}])assert.throws(()=>validateSchedule({...input,...bad},6,1000)); }); test('chain configuration targets Robinhood mainnet with its matching explorer',()=>{ assert.equal(Number(CHAIN.chainId),4663); assert.equal(CHAIN.rpcUrls[0],'https://rpc.mainnet.chain.robinhood.com'); assert.equal(CHAIN.blockExplorerUrls[0],'https://robinhoodchain.blockscout.com'); assert.equal(CHAIN.nativeCurrency.symbol,'ETH'); });