import { keccak } from 'hash-wasm'; const alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; const decodedSizes:Record={2:1,3:2,5:3,6:4,7:5,9:6,10:7,11:8}; /** Support only mainnet standard/subaddresses. Integrated/payment-ID addresses need a separate policy. */ export async function validateXmrAddress(address:string):Promise{ if(typeof address!=='string'||address.length!==95)throw new Error('Expected a mainnet standard XMR address or subaddress'); const bytes:number[]=[]; for(let start=0;start(size).fill(0); for(let i=size-1;i>=0;i--){output[i]=Number(value&255n);value>>=8n;} if(value)throw new Error('XMR Base58 block overflow');bytes.push(...output); } if(bytes.length!==69||![18,42].includes(bytes[0]))throw new Error('XMR address network/type is not supported'); const decoded=Uint8Array.from(bytes),expected=(await keccak(decoded.slice(0,-4),256)).slice(0,8); if(Buffer.from(decoded.slice(-4)).toString('hex')!==expected)throw new Error('XMR checksum mismatch'); return address; } export function atomicXmr(value:string):bigint{ if(typeof value!=='string'||!/^(0|[1-9]\d{0,9})(\.\d{1,12})?$/.test(value))throw new Error('Invalid bounded XMR decimal'); const [whole,fraction='']=value.split('.');return BigInt(whole)*1_000_000_000_000n+BigInt(fraction.padEnd(12,'0')); } export function fiatCents(value:string):number{ if(typeof value!=='string'||!/^(0|[1-9]\d{0,6})(\.\d{1,2})?$/.test(value))throw new Error('Invalid USD decimal'); const [whole,fraction='']=value.split('.');return Number(whole)*100+Number(fraction.padEnd(2,'0')); }