@nullpay/mcp 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/aleo.js +49 -39
  2. package/package.json +1 -1
package/dist/aleo.js CHANGED
@@ -24,7 +24,8 @@ const crypto_1 = __importDefault(require("crypto"));
24
24
  const esm_1 = require("./esm");
25
25
  const env_1 = require("./env");
26
26
  exports.PROGRAM_ID = 'zk_pay_proofs_privacy_v22.aleo';
27
- const FREEZELIST_PROGRAM_ID = 'test_usdcx_freezelist.aleo';
27
+ const USDCX_FREEZELIST_PROGRAM_ID = 'test_usdcx_freezelist.aleo';
28
+ const USAD_FREEZELIST_PROGRAM_ID = 'test_usad_freezelist.aleo';
28
29
  const EXPLORER_BASE = 'https://api.explorer.provable.com/v1';
29
30
  const MAPPING_BASE = 'https://api.provable.com/v2/testnet/program';
30
31
  const SCANNER_BASE = 'https://api.provable.com/scanner/testnet';
@@ -548,43 +549,54 @@ async function findSpendableRecord(session, programFilter, recordName, amountReq
548
549
  }
549
550
  return null;
550
551
  }
551
- async function getFreezeListIndex(index) {
552
+ function getFreezeListProgramId(tokenProgram) {
553
+ if (tokenProgram === 'test_usdcx_stablecoin.aleo') {
554
+ return USDCX_FREEZELIST_PROGRAM_ID;
555
+ }
556
+ if (tokenProgram === 'test_usad_stablecoin.aleo') {
557
+ return USAD_FREEZELIST_PROGRAM_ID;
558
+ }
559
+ return null;
560
+ }
561
+ async function getFreezeListIndex(programId, index) {
552
562
  const { AleoNetworkClient } = await (0, esm_1.dynamicImport)('@provablehq/sdk');
553
563
  const client = new AleoNetworkClient(EXPLORER_BASE);
554
- const value = await client.getProgramMappingValue(FREEZELIST_PROGRAM_ID, 'freeze_list_index', `${index}u32`);
564
+ const value = await client.getProgramMappingValue(programId, 'freeze_list_index', `${index}u32`);
555
565
  return value ? value.replace(/"/g, '') : null;
556
566
  }
557
- async function generateFreezeListProof(targetIndex = 1, occupiedLeafValue) {
558
- const { Plaintext } = await (0, esm_1.dynamicImport)('@provablehq/sdk');
559
- const { Poseidon4 } = await (0, esm_1.dynamicImport)('@provablehq/wasm');
560
- const hasher = new Poseidon4();
561
- const emptyHashes = [];
562
- let currentEmpty = '0field';
563
- const hashFields = (values) => {
564
- const plaintext = Plaintext.fromString(`[${values.join(', ')}]`);
565
- return hasher.hash(plaintext.toFields()).toString();
566
- };
567
- for (let level = 0; level < 16; level += 1) {
568
- emptyHashes.push(currentEmpty);
569
- currentEmpty = hashFields([currentEmpty, currentEmpty]);
570
- }
571
- let currentHash = '0field';
572
- let currentIndex = targetIndex;
573
- const proofSiblings = [];
574
- for (let level = 0; level < 16; level += 1) {
575
- const isLeft = currentIndex % 2 === 0;
576
- const siblingIndex = isLeft ? currentIndex + 1 : currentIndex - 1;
577
- let siblingHash = emptyHashes[level];
578
- if (level === 0 && siblingIndex === 0 && occupiedLeafValue) {
579
- siblingHash = occupiedLeafValue;
567
+ async function getFreezeListCount(programId) {
568
+ const response = await fetch(`${MAPPING_BASE}/${programId}/mapping/freeze_list_last_index/true`);
569
+ if (!response.ok) {
570
+ return 0;
571
+ }
572
+ const value = await response.json();
573
+ if (!value) {
574
+ return 0;
575
+ }
576
+ const parsed = Number.parseInt(String(value).replace(/u32|["']/g, ''), 10);
577
+ return Number.isFinite(parsed) ? parsed + 1 : 0;
578
+ }
579
+ async function generateFreezeListProof(ownerAddress, tokenProgram) {
580
+ const freezeListProgramId = getFreezeListProgramId(tokenProgram);
581
+ if (!freezeListProgramId) {
582
+ throw new Error(`Unsupported freeze list program for ${tokenProgram}`);
583
+ }
584
+ const { SealanceMerkleTree } = await (0, esm_1.dynamicImport)('@provablehq/sdk');
585
+ const count = Math.max(1, await getFreezeListCount(freezeListProgramId));
586
+ const addresses = [];
587
+ for (let index = 0; index < count; index += 1) {
588
+ const address = await getFreezeListIndex(freezeListProgramId, index);
589
+ if (address) {
590
+ addresses.push(address);
580
591
  }
581
- proofSiblings.push(siblingHash);
582
- currentHash = isLeft
583
- ? hashFields([currentHash, siblingHash])
584
- : hashFields([siblingHash, currentHash]);
585
- currentIndex = Math.floor(currentIndex / 2);
586
592
  }
587
- return `{ siblings: [${proofSiblings.join(', ')}], leaf_index: ${targetIndex}u32 }`;
593
+ const sealance = new SealanceMerkleTree();
594
+ const leaves = sealance.generateLeaves(addresses, 16);
595
+ const tree = sealance.buildTree(leaves);
596
+ const [leftIdx, rightIdx] = sealance.getLeafIndices(tree, ownerAddress);
597
+ const proofLeft = sealance.getSiblingPath(tree, leftIdx, 16);
598
+ const proofRight = sealance.getSiblingPath(tree, rightIdx, 16);
599
+ return sealance.formatMerkleProof([proofLeft, proofRight]);
588
600
  }
589
601
  async function createSponsoredPaymentAuthorization(args) {
590
602
  const session = await getScannerSession(args.walletPrivateKey);
@@ -602,14 +614,12 @@ async function createSponsoredPaymentAuthorization(args) {
602
614
  }
603
615
  let proofsInput;
604
616
  if (paymentMode.tokenProgram !== 'credits.aleo') {
605
- const firstIndex = await getFreezeListIndex(0);
606
- let index0Field;
607
- if (firstIndex) {
608
- const { Address } = await (0, esm_1.dynamicImport)('@provablehq/wasm');
609
- index0Field = Address.from_string(firstIndex).toGroup().toXCoordinate().toString();
617
+ const ownerMatch = record.match(/owner\s*:\s*([a-z0-9]+)/i);
618
+ const ownerAddress = ownerMatch?.[1];
619
+ if (!ownerAddress || !ownerAddress.startsWith('aleo')) {
620
+ throw new Error(`Failed to read token record owner for ${paymentMode.tokenProgram}.`);
610
621
  }
611
- const proof = await generateFreezeListProof(1, index0Field);
612
- proofsInput = `[${proof}, ${proof}]`;
622
+ proofsInput = await generateFreezeListProof(ownerAddress, paymentMode.tokenProgram);
613
623
  }
614
624
  const { AleoKeyProvider, AleoNetworkClient, NetworkRecordProvider, ProgramManager } = await (0, esm_1.dynamicImport)('@provablehq/sdk');
615
625
  const keyProvider = new AleoKeyProvider();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullpay/mcp",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "NullPay MCP server and Claude setup wizard for conversational payment flows",
5
5
  "type": "commonjs",
6
6
  "main": "dist/server.js",