UNPKG

@shubhamrasal/groundline

Version:
170 lines 7.84 kB
import { Synapse, RPC_URLS, CONTRACT_ADDRESSES, PandoraService } from '@filoz/synapse-sdk'; import { ethers } from 'ethers'; // Constants const PROOF_SET_CREATION_FEE = ethers.parseUnits('5', 18); // 5 USDFC for proof set const BUFFER_AMOUNT = ethers.parseUnits('5', 18); // 5 USDFC buffer for gas fees export class IPFSClient { constructor(config = {}) { this.config = config; } /** * Performs preflight checks to ensure sufficient USDFC balance and allowances * @param dataSize Size of data to be stored * @param withProofset Whether a new proofset needs to be created */ async performPreflightCheck(dataSize, withProofset) { const network = this.synapse.getNetwork(); const pandoraAddress = CONTRACT_ADDRESSES.PANDORA_SERVICE[network]; const signer = this.synapse.getSigner(); if (!signer || !signer.provider) { throw new Error("Provider not found"); } // Initialize Pandora service for allowance checks const pandoraService = new PandoraService(signer.provider, pandoraAddress); // Check if current allowance is sufficient const preflight = await pandoraService.checkAllowanceForStorage(dataSize, this.config.withCDN || false, this.synapse.payments); // If allowance is insufficient, handle deposit and approval if (!preflight.sufficient) { // Calculate total allowance needed including proofset creation fee if required const proofSetCreationFee = withProofset ? PROOF_SET_CREATION_FEE : BigInt(0); const allowanceNeeded = preflight.lockupAllowanceNeeded + proofSetCreationFee + BUFFER_AMOUNT; console.log('Setting up USDFC payments:'); console.log('- Base allowance:', ethers.formatUnits(preflight.lockupAllowanceNeeded, 18), 'USDFC'); if (withProofset) { console.log('- Proof set fee:', ethers.formatUnits(PROOF_SET_CREATION_FEE, 18), 'USDFC'); } console.log('- Buffer amount:', ethers.formatUnits(BUFFER_AMOUNT, 18), 'USDFC'); console.log('- Total needed:', ethers.formatUnits(allowanceNeeded, 18), 'USDFC'); // Step 1: Deposit USDFC to cover storage costs console.log('Depositing USDFC...'); await this.synapse.payments.deposit(allowanceNeeded); console.log('USDFC deposited successfully'); // Step 2: Approve Pandora service to spend USDFC at specified rates console.log('Approving Pandora service...'); await this.synapse.payments.approveService(pandoraAddress, preflight.rateAllowanceNeeded, allowanceNeeded); console.log('Pandora service approved successfully'); } else { console.log('✓ Sufficient USDFC allowance already available'); } } /** * Initialize the IPFS client with Synapse SDK */ async initialize() { // Initialize Synapse SDK this.synapse = await Synapse.create({ privateKey: this.config.privateKey, rpcURL: this.config.rpcURL || RPC_URLS.calibration.websocket, withCDN: this.config.withCDN }); // Perform initial preflight check with minimum size for proof set creation await this.performPreflightCheck(1024, true); // 1KB minimum size // Create storage service with callbacks try { this.storage = await this.synapse.createStorage({ callbacks: { onProviderSelected: (provider) => { console.log(`✓ Selected storage provider: ${provider.owner}`); console.log(` PDP URL: ${provider.pdpUrl}`); }, onProofSetResolved: (info) => { if (info.isExisting) { console.log(`✓ Using existing proof set: ${info.proofSetId}`); } else { console.log(`✓ Created new proof set: ${info.proofSetId}`); } }, onProofSetCreationStarted: (transaction, statusUrl) => { console.log(` Creating proof set, tx: ${transaction.hash}`); }, onProofSetCreationProgress: (status) => { if (status.transactionMined && !status.proofSetLive) { console.log(' Transaction mined, waiting for proof set to be live...'); } }, }, }); } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; console.error('Storage service creation failed:', error); throw new Error(`Failed to create storage service: ${message}`); } } /** * Upload graph snapshot to IPFS * @param snapshot Graph data to store * @returns CID of the stored content */ async uploadSnapshot(snapshot) { try { // Convert Maps to plain objects for JSON serialization const serializedSnapshot = { ...snapshot, nodes: Object.fromEntries(snapshot.nodes), edges: Object.fromEntries(snapshot.edges) }; // Convert to Uint8Array for upload const data = new TextEncoder().encode(JSON.stringify(serializedSnapshot)); // Create a promise that resolves when upload is complete return new Promise((resolve, reject) => { this.storage.upload(data, { onUploadComplete(commp) { console.log(`✓ Upload complete: ${commp}`); resolve(commp.toString()); return commp.toString(); }, }).catch(reject); }); } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; throw new Error(`Failed to upload snapshot: ${message}`); } } /** * Retrieve graph snapshot from IPFS * @param cid Content identifier (CommP) * @returns Graph snapshot data */ async getSnapshot(cid) { try { // Download data from IPFS via Synapse const data = await this.storage.providerDownload(cid); // Parse the JSON data const serializedSnapshot = JSON.parse(new TextDecoder().decode(data)); // Convert plain objects back to Maps return { ...serializedSnapshot, nodes: new Map(Object.entries(serializedSnapshot.nodes)), edges: new Map(Object.entries(serializedSnapshot.edges)) }; } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; throw new Error(`Failed to retrieve snapshot: ${message}`); } } /** * Pin content to ensure persistence * @param cid Content identifier to pin */ async pinContent(cid) { try { // In Synapse, content is automatically pinned by the storage provider // We can optionally verify the piece is available await this.storage.providerDownload(cid, { onlyVerify: true }); } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; throw new Error(`Failed to verify content: ${message}`); } } } // Export a factory function for creating IPFS client instances export function createIPFSClient(config) { return new IPFSClient(config); } //# sourceMappingURL=ipfs.js.map