@nullpay/mcp 1.0.3 → 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.
- package/dist/aleo.js +49 -35
- package/dist/service.js +18 -6
- 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
|
|
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,39 +549,54 @@ async function findSpendableRecord(session, programFilter, recordName, amountReq
|
|
|
548
549
|
}
|
|
549
550
|
return null;
|
|
550
551
|
}
|
|
551
|
-
|
|
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(
|
|
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
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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);
|
|
576
591
|
}
|
|
577
|
-
proofSiblings.push(siblingHash);
|
|
578
|
-
const left = Field.fromString(isLeft ? currentHash : siblingHash);
|
|
579
|
-
const right = Field.fromString(isLeft ? siblingHash : currentHash);
|
|
580
|
-
currentHash = hasher.hash([left, right]).toString();
|
|
581
|
-
currentIndex = Math.floor(currentIndex / 2);
|
|
582
592
|
}
|
|
583
|
-
|
|
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]);
|
|
584
600
|
}
|
|
585
601
|
async function createSponsoredPaymentAuthorization(args) {
|
|
586
602
|
const session = await getScannerSession(args.walletPrivateKey);
|
|
@@ -598,14 +614,12 @@ async function createSponsoredPaymentAuthorization(args) {
|
|
|
598
614
|
}
|
|
599
615
|
let proofsInput;
|
|
600
616
|
if (paymentMode.tokenProgram !== 'credits.aleo') {
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
if (
|
|
604
|
-
|
|
605
|
-
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}.`);
|
|
606
621
|
}
|
|
607
|
-
|
|
608
|
-
proofsInput = `[${proof}, ${proof}]`;
|
|
622
|
+
proofsInput = await generateFreezeListProof(ownerAddress, paymentMode.tokenProgram);
|
|
609
623
|
}
|
|
610
624
|
const { AleoKeyProvider, AleoNetworkClient, NetworkRecordProvider, ProgramManager } = await (0, esm_1.dynamicImport)('@provablehq/sdk');
|
|
611
625
|
const keyProvider = new AleoKeyProvider();
|
package/dist/service.js
CHANGED
|
@@ -235,18 +235,27 @@ class NullPayMcpService {
|
|
|
235
235
|
let recoveredEncryptedBurnerKey = null;
|
|
236
236
|
let usedRecoveredPassword = false;
|
|
237
237
|
let restoredBurnerFromChain = false;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
let chainBackupLoaded = false;
|
|
239
|
+
const loadChainBackup = async () => {
|
|
240
|
+
if (chainBackupLoaded || !mainPrivateKey) {
|
|
241
|
+
return null;
|
|
241
242
|
}
|
|
243
|
+
chainBackupLoaded = true;
|
|
242
244
|
const recovered = await (0, aleo_1.recoverOnChainWalletBackup)(mainPrivateKey, address);
|
|
243
|
-
if (!recovered
|
|
244
|
-
return
|
|
245
|
+
if (!recovered) {
|
|
246
|
+
return null;
|
|
245
247
|
}
|
|
246
|
-
password = recovered.password;
|
|
247
248
|
recoveredBackupSource = recovered.source;
|
|
248
249
|
recoveredBurnerAddress = recovered.burnerAddress || null;
|
|
249
250
|
recoveredEncryptedBurnerKey = recovered.encryptedBurnerKey || null;
|
|
251
|
+
return recovered;
|
|
252
|
+
};
|
|
253
|
+
const attemptRecovery = async () => {
|
|
254
|
+
const recovered = await loadChainBackup();
|
|
255
|
+
if (!recovered?.password) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
password = recovered.password;
|
|
250
259
|
usedRecoveredPassword = true;
|
|
251
260
|
return true;
|
|
252
261
|
};
|
|
@@ -302,6 +311,9 @@ class NullPayMcpService {
|
|
|
302
311
|
burnerAddress = null;
|
|
303
312
|
}
|
|
304
313
|
}
|
|
314
|
+
if (!encryptedBurnerKey || !burnerAddress || !encryptedBurnerAddress) {
|
|
315
|
+
await loadChainBackup();
|
|
316
|
+
}
|
|
305
317
|
if ((!encryptedBurnerAddress || !encryptedBurnerKey || !burnerAddress) && recoveredBurnerAddress && recoveredEncryptedBurnerKey) {
|
|
306
318
|
burnerAddress = recoveredBurnerAddress;
|
|
307
319
|
encryptedBurnerAddress = await (0, crypto_1.encryptWithPassword)(recoveredBurnerAddress, password);
|