nestai-framework
Version:
Unlocking Next-Gen AI Agents with N.E.S.T.
138 lines (116 loc) • 5.16 kB
text/typescript
import { VersionedTransaction, Connection, Keypair } from "@solana/web3.js";
import bs58 from "bs58";
import * as dotenv from "dotenv";
import fs from "fs";
import fetch from "node-fetch";
import { agentDetails } from "./defineNestAI.js";
import { checkAgentExists, storeAgent } from "../firebase.js";
dotenv.config();
const RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";
const web3Connection = new Connection(RPC_ENDPOINT, "confirmed");
// Define the expected structure of the metadata response
interface MetadataResponse {
metadata: {
name: string;
symbol: string;
};
metadataUri: string;
}
/**
* Sends a local create transaction for an agent's token and metadata.
* This includes checking if the agent already exists, uploading metadata,
* creating the token on Solana, and saving agent details to Firebase.
*/
async function sendLocalCreateTx() {
const agentName = agentDetails.name;
// Step 1: Check if the agent already exists in the system
const agentExists = await checkAgentExists(agentName);
if (agentExists) {
console.error(`Agent "${agentName}" already exists. Please try another name.`);
return;
}
// Step 2: Validate and decode private key for the signer
const secretKey = process.env.PK;
if (!secretKey) {
throw new Error("PK is not set in the .env file! Please set your private key.");
}
const signerKeyPair = Keypair.fromSecretKey(bs58.decode(secretKey));
// Step 3: Generate a new mint keypair for the token
const mintKeypair = Keypair.generate();
// Step 4: Upload metadata to IPFS using form data
const metadataResponseJSON = await uploadMetadata();
// Step 5: Create the token on Solana with the metadata URI
await createSolanaToken(signerKeyPair, mintKeypair, metadataResponseJSON);
// Step 6: Store the agent details in Firebase
await storeAgent(agentName, {
...agentDetails,
mintAddress: mintKeypair.publicKey.toBase58(),
personality: agentDetails.personality
});
console.log(`Agent "${agentName}" and mint address saved to Firebase.`);
}
/**
* Uploads metadata (including image and description) to IPFS.
* @returns The response from the metadata upload API, including metadata and URI.
*/
async function uploadMetadata(): Promise<MetadataResponse> {
const FormData = (await import("form-data")).default;
const formData = new FormData();
formData.append("file", fs.createReadStream(agentDetails.imagePath));
formData.append("name", agentDetails.name);
formData.append("symbol", agentDetails.symbol);
const modifiedDescription = `${agentDetails.description}\n\nPowered by NestAI`;
formData.append("description", modifiedDescription);
const metadataResponse = await fetch("https://pump.fun/api/ipfs", {
method: "POST",
body: formData,
headers: formData.getHeaders(),
});
if (!metadataResponse.ok) {
throw new Error(`Failed to upload metadata: ${metadataResponse.statusText}`);
}
// Type casting the response to match the expected structure
return metadataResponse.json() as Promise<MetadataResponse>;
}
/**
* Creates a token on the Solana blockchain using the provided signer and mint keypair.
* @param signerKeyPair - The keypair of the signer (agent owner)
* @param mintKeypair - The keypair for the new token mint
* @param metadataResponseJSON - The response containing the metadata URI
*/
async function createSolanaToken(signerKeyPair: Keypair, mintKeypair: Keypair, metadataResponseJSON: MetadataResponse) {
const response = await fetch("https://pumpportal.fun/api/trade-local", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
publicKey: signerKeyPair.publicKey.toBase58(),
action: "create",
tokenMetadata: {
name: metadataResponseJSON.metadata.name,
symbol: metadataResponseJSON.metadata.symbol,
uri: metadataResponseJSON.metadataUri,
},
mint: mintKeypair.publicKey.toBase58(),
denominatedInSol: "true",
amount: agentDetails.initialBuyAmount,
slippage: 10,
priorityFee: 0.0005,
pool: "pump",
}),
});
if (!response.ok) {
throw new Error(`Error creating token: ${response.statusText}`);
}
const data = await response.arrayBuffer();
const tx = VersionedTransaction.deserialize(new Uint8Array(data));
tx.sign([mintKeypair, signerKeyPair]);
// Send the transaction to the Solana network
const signature = await web3Connection.sendTransaction(tx);
console.log(`Transaction successful: https://solscan.io/tx/${signature}`);
}
/**
* Main function to initiate the creation of the agent's token and metadata.
*/
sendLocalCreateTx().catch((error) => {
console.error("An error occurred during deployment:", error.message || error);
});