@lit-protocol/vincent-scaffold-sdk
Version:
Shared build configuration and utilities for Vincent tools and policies
131 lines (115 loc) • 4.16 kB
JavaScript
const fs = require("fs");
const path = require("path");
/**
* Deploy Lit Action to IPFS using Pinata
* Reads the bundled Lit Action code and deploys it to IPFS, then validates against existing metadata
* @param {Object} options - Configuration options
* @param {string} [options.pinataJwt] - Pinata JWT token (defaults to process.env.PINATA_JWT)
* @param {string} [options.outputFile] - Output filename (defaults to 'lit-action.js')
* @param {string} [options.generatedDir] - Generated directory path (defaults to '../src/generated')
* @param {string} [options.projectType] - Project type ('tool' or 'policy') to determine metadata filename
* @returns {Promise<string>} Promise that resolves to the IPFS CID
*/
async function deployLitAction(options = {}) {
const {
pinataJwt = process.env.PINATA_JWT,
outputFile = "lit-action.js",
generatedDir = path.join(__dirname, "../src/generated"),
projectType = "tool",
} = options;
// Validate Pinata JWT
if (!pinataJwt) {
throw new Error(
"❌ PINATA_JWT environment variable is not set in root .env file or provided as parameter"
);
}
try {
const filePath = path.join(generatedDir, outputFile);
if (!fs.existsSync(filePath)) {
throw new Error(
`❌ Bundled Lit Action code string not found at ${filePath}. Please run pnpx nx run vincent-tool-erc20-approval:action:build first.`
);
}
// Import ES module dynamically
const litActionCodeString = await import(filePath);
console.log(`Deploying ${outputFile} to IPFS...`);
const ipfsCid = await uploadToIPFS(
outputFile,
litActionCodeString.default.code,
pinataJwt
);
const metadataFilename =
projectType === "policy"
? "vincent-policy-metadata.json"
: "vincent-tool-metadata.json";
const cidJsonPath = path.join(generatedDir, metadataFilename);
const metadata = fs.readFileSync(cidJsonPath);
const { ipfsCid: metadataIpfsCid } = JSON.parse(metadata);
if (ipfsCid !== metadataIpfsCid) {
throw new Error(
`❌ IPFS CID mismatch in vincent-policy-metadata.json. Expected: ${metadataIpfsCid}, got: ${ipfsCid}`
);
}
// const cidJsonContent = {
// ipfsCid,
// };
// fs.writeFileSync(cidJsonPath, JSON.stringify(cidJsonContent, null, 2), 'utf8');
console.log("✅ Successfully deployed Lit Action");
console.log(`ℹ️ Deployed ${outputFile} to IPFS: ${ipfsCid}`);
console.log(`🔗 https://explorer.litprotocol.com/ipfs/${ipfsCid}`);
// console.log(`ℹ️ Saved vincent-tool-metadata.json to: ${cidJsonPath}`);
return ipfsCid;
} catch (error) {
console.error("❌ Error in deploy process:", error);
throw error;
}
}
/**
* Upload file content to IPFS via Pinata
* @param {string} filename - Name of the file
* @param {string} fileContent - Content of the file
* @param {string} pinataJwt - Pinata JWT token
* @returns {Promise<string>} Promise that resolves to the IPFS hash
*/
async function uploadToIPFS(filename, fileContent, pinataJwt) {
try {
const form = new FormData();
form.append(
"file",
new Blob([fileContent], { type: "application/javascript" }),
filename
);
const response = await fetch(
"https://api.pinata.cloud/pinning/pinFileToIPFS",
{
method: "POST",
headers: {
Authorization: `Bearer ${pinataJwt}`,
},
body: form,
}
);
if (!response.ok) {
const text = await response.text();
throw new Error(`HTTP error! status: ${response.status} - ${text}`);
}
const data = await response.json();
return data.IpfsHash;
} catch (error) {
console.error("Error uploading to IPFS:", error);
throw error;
}
}
// Export the main function
module.exports = deployLitAction;
// // Run the deployment if this script is executed directly
// if (require.main === module) {
// (async () => {
// try {
// await deployLitAction();
// } catch (error) {
// console.error("❌ Error in deploy process:", error);
// process.exit(1);
// }
// })();
// }