import { describe, it, expect } from 'vitest'; import { Runestone } from '@saturnbtcio/ordinals-lib'; import { validateRunestoneEdictsAndAmounts } from './one-to-zero.validation'; describe('validateRunestoneEdictsAndAmounts with provided PSBT', () => { it('deciphers PSBT and validates collectionId, amountOut, and totals', () => { const signedPsbt = 'cHNidP8BAP0OAwIAAAABYIxd+/PVWmlW2+yg6lmhzTgYybXWSFByfW5L+8xCGAoHAAAAAP////8RIgIAAAAAAAAiUSBDtG3yDw4N73rdMipYqu3vj3tX9q10jEElDcbfFHe4/CICAAAAAAAAIlEg6YkW3ngRWYZDM7mUA+tbd4n8s0rclyOgWgKfkSPuhA8iAgAAAAAAACJRIN11MMilztqLW3YFUcsx0MfG0uuTm8uFQhvHmcKpDwVWIgIAAAAAAAAiUSBTfTctM90BNBvB/LIHJjPGPGPm1c8HMNru/ofWP7RrpCICAAAAAAAAIlEgrh3N9MBZKPuZteswDPoexku1HF2fmj0JjXwc0J6hCtMiAgAAAAAAACJRIIdIvWlxCeaBKdsmOWJvZ2SMaMAtnzdDMeLwwbFnh4RLIgIAAAAAAAAiUSDpeBg33pegt0QDkhQ9QcMpBhGbxX9HU1osJ8fPWLq1OiICAAAAAAAAIlEgd0e+CVhI9hYXDN6QJUWVKQgb7pFgQhGLsoh2jIVUeKgiAgAAAAAAACJRIHdHvglYSPYWFwzekCVFlSkIG+6RYEIRi7KIdoyFVHioIgIAAAAAAAAiUSB3R74JWEj2FhcM3pAlRZUpCBvukWBCEYuyiHaMhVR4qCICAAAAAAAAIlEgd0e+CVhI9hYXDN6QJUWVKQgb7pFgQhGLsoh2jIVUeKgiAgAAAAAAACJRIHdHvglYSPYWFwzekCVFlSkIG+6RYEIRi7KIdoyFVHioIgIAAAAAAAAiUSB3R74JWEj2FhcM3pAlRZUpCBvukWBCEYuyiHaMhVR4qCICAAAAAAAAIlEgLMEL8H7D/Ymsuv+l9OAFVtlkHKQyOAtapDeKt3Zi7Dn0hgEAAAAAACJRIHdHvglYSPYWFwzekCVFlSkIG+6RYEIRi7KIdoyFVHioAAAAAAAAAAAial0fFgcAia4DDCkIAAApCQAAKQoAACoLAACQAQwAAMxBDaqcAAAAAAAAIlEgLMEL8H7D/Ymsuv+l9OAFVtlkHKQyOAtapDeKt3Zi7DkAAAAAAAEBK0AvAgAAAAAAIlEgLMEL8H7D/Ymsuv+l9OAFVtlkHKQyOAtapDeKt3Zi7DkBAwSBAAAAARNBkufl5tJ0kdNJv8ru1uNv0RcYppY71q+PKtI9bmkPJWG+wbNVmdv6M8FgSxETX7N+gtpYeV1PKzeVRvAKM22cE4EBFyCY5MYdZ2MkIeehFAxiA9ed36BZTJoDHIiTX5phggr7lAAAAAAAAAAAAAAAAAAAAAAAAA==' const runestone = Runestone.decipher(signedPsbt)!; // Provided expectations const collectionId = '55049:12'; const amountOut = 8396n; const totalRuneAmountInShards = 8746n; // Dump runestone details for debugging const script = runestone.encipher(); console.log('runestone.script.length', script.length); console.log('runestone.pointer', runestone.pointer); console.log( 'runestone.edicts', runestone.edicts.map((e: any, i: number) => ({ i, block: e.id.block, tx: e.id.tx, amount: e.amount, output: e.output, })), ); // Reproduce the validation math to see why it fails const programEdicts = runestone.edicts.length > 1 ? runestone.edicts.slice(0, runestone.edicts.length - 1) : []; const programAmounts = programEdicts.map((e: any) => e.amount as bigint); const totalProgram = programAmounts.reduce((a: bigint, b: bigint) => a + b, 0n); const remainder = totalRuneAmountInShards - totalProgram - amountOut; const amountsForThreshold = [...programAmounts, remainder]; const totalForThreshold = amountsForThreshold.reduce((a, b) => a + b, 0n); const ideal = totalForThreshold / BigInt(amountsForThreshold.length); const thresholdPercent = 50n; const acceptableDeviation = (thresholdPercent * ideal + 99n) / 100n; const diffs = amountsForThreshold.map((x) => (x > ideal ? x - ideal : ideal - x)); console.log('programAmounts', programAmounts); console.log('totalProgram', totalProgram.toString()); console.log('amountOut', amountOut.toString()); console.log('totalRuneAmountInShards', totalRuneAmountInShards.toString()); console.log('remainder', remainder.toString()); console.log('ideal', ideal.toString()); console.log('acceptableDeviation', acceptableDeviation.toString()); console.log('diffs', diffs.map((d) => d.toString())); // This signed PSBT is expected to fail the fairness threshold validation expect(() => validateRunestoneEdictsAndAmounts( runestone, collectionId, amountOut, totalRuneAmountInShards, ), ).toThrowError(/Amounts are not within threshold/); }); });