diff --git a/.env.example b/.env.example index dba7768..1f3564b 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ -OPENAI_API_KEY=your_openai_api_key_here -RPC_URL=your_rpc_url_here -SOLANA_PRIVATE_KEY=your_solana_private_key_here +OPENAI_API_KEY= +RPC_URL= +SOLANA_PRIVATE_KEY= diff --git a/package.json b/package.json index 47db16c..7815243 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "tsc", "docs": "typedoc src --out docs", "test": "ts-node test/index.ts", + "test:tools": "ts-node test/tools.ts", "generate": "ts-node src/utils/keypair.ts" }, "keywords": [], @@ -37,4 +38,4 @@ "@types/node": "^22.9.0", "ts-node": "^10.9.2" } -} +} \ No newline at end of file diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 8fa356d..2b48d28 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -88,7 +88,7 @@ export class SolanaTransferTool extends Tool { export class SolanaDeployTokenTool extends Tool { name = "solana_deploy_token"; description = - "Deploy a new SPL token. Input should be JSON string with: {decimals?: number, initialSupply?: number}"; + "Deploy a new SPL token. Input should be JSON string with: {decimals?: number, name: string, uri: string, symbol: string, initialSupply?: number}"; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -118,7 +118,7 @@ export class SolanaDeployTokenTool extends Tool { const parsedInput = toJSON(input); this.validateInput(parsedInput); - const result = await this.solanaKit.deployToken(parsedInput.decimals); + const result = await this.solanaKit.deployToken(parsedInput.decimals, parsedInput.name, parsedInput.uri, parsedInput.symbol, parsedInput.initialSupply); return JSON.stringify({ status: "success", @@ -442,7 +442,7 @@ export class SolanaGetDomainTool extends Tool { try { const account = new PublicKey(input.trim()); const domain = await this.solanaKit.getPrimaryDomain(account); - + return JSON.stringify({ status: "success", message: "Primary domain retrieved successfully", diff --git a/src/tools/deploy_collection.ts b/src/tools/deploy_collection.ts index 1b649ab..4528b92 100644 --- a/src/tools/deploy_collection.ts +++ b/src/tools/deploy_collection.ts @@ -1,8 +1,8 @@ import { SolanaAgentKit } from "../index"; -import { generateSigner, publicKey } from "@metaplex-foundation/umi"; +import { generateSigner, keypairIdentity, publicKey } from "@metaplex-foundation/umi"; import { createCollection, mplCore, ruleSet } from "@metaplex-foundation/mpl-core"; import { CollectionOptions, CollectionDeployment } from "../types"; -import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import { fromWeb3JsKeypair, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; /** @@ -18,6 +18,7 @@ export async function deploy_collection( try { // Initialize Umi const umi = createUmi(agent.connection.rpcEndpoint).use(mplCore()); + umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet))); // Generate collection signer const collectionSigner = generateSigner(umi); diff --git a/src/tools/deploy_token.ts b/src/tools/deploy_token.ts index b1f78ff..3383f16 100644 --- a/src/tools/deploy_token.ts +++ b/src/tools/deploy_token.ts @@ -1,9 +1,9 @@ import { SolanaAgentKit } from "../index"; import { PublicKey } from "@solana/web3.js"; import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; -import { generateSigner } from "@metaplex-foundation/umi"; +import { generateSigner, keypairIdentity } from "@metaplex-foundation/umi"; import { createFungible, mintV1, TokenStandard } from "@metaplex-foundation/mpl-token-metadata"; -import { fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; /** * Deploy a new SPL token @@ -26,6 +26,7 @@ export async function deploy_token( try { // Create UMI instance from agent const umi = createUmi(agent.connection.rpcEndpoint) + umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet))); // Create new token mint const mint = generateSigner(umi); @@ -55,7 +56,7 @@ export async function deploy_token( })); } - builder.sendAndConfirm(umi); + builder.sendAndConfirm(umi, { confirm: { commitment: 'finalized' } }); console.log( "Token deployed successfully. Mint address: ", diff --git a/src/tools/mint_nft.ts b/src/tools/mint_nft.ts index 395032d..09bfe32 100644 --- a/src/tools/mint_nft.ts +++ b/src/tools/mint_nft.ts @@ -1,9 +1,9 @@ import { SolanaAgentKit } from "../index"; -import { generateSigner } from '@metaplex-foundation/umi'; -import { create } from '@metaplex-foundation/mpl-core'; +import { generateSigner, keypairIdentity } from '@metaplex-foundation/umi'; +import { create, mplCore } from '@metaplex-foundation/mpl-core'; import { fetchCollection } from '@metaplex-foundation/mpl-core'; import { PublicKey } from "@solana/web3.js"; -import { fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { MintCollectionNFTResponse } from '../types'; @@ -20,7 +20,6 @@ export async function mintCollectionNFT( collectionMint: PublicKey, metadata: { name: string; - symbol: string; uri: string; sellerFeeBasisPoints?: number; creators?: Array<{ @@ -32,7 +31,8 @@ export async function mintCollectionNFT( ): Promise { try { // Create UMI instance from agent - const umi = createUmi(agent.connection.rpcEndpoint) + const umi = createUmi(agent.connection.rpcEndpoint).use(mplCore()); + umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet))); // Convert collection mint to UMI format const umiCollectionMint = fromWeb3JsPublicKey(collectionMint); @@ -49,7 +49,7 @@ export async function mintCollectionNFT( collection: collection, name: metadata.name, uri: metadata.uri, - owner: fromWeb3JsPublicKey(recipient!) + owner: fromWeb3JsPublicKey(recipient ?? agent.wallet.publicKey) }).sendAndConfirm(umi); return { diff --git a/test/deployCollection.ts b/test/deployCollection.ts new file mode 100644 index 0000000..df776d8 --- /dev/null +++ b/test/deployCollection.ts @@ -0,0 +1,30 @@ +import { SolanaAgentKit } from "../src"; +import { deploy_collection } from "../src/tools"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { fromWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import assert from "assert"; +import { fetchCollection, mplCore } from "@metaplex-foundation/mpl-core"; + +export async function test_deploy_collection() { + console.log("<<< Test Deploy Collection"); + const solanaKit = new SolanaAgentKit( + process.env.SOLANA_PRIVATE_KEY!, + process.env.RPC_URL, + process.env.OPENAI_API_KEY! + ); + + const umi = createUmi(solanaKit.connection.rpcEndpoint).use(mplCore()); + + const collectionAddress = fromWeb3JsPublicKey((await deploy_collection(solanaKit, { + name: "test", + uri: "www.example.com", + })).collectionAddress); + + const collection = await fetchCollection(umi, collectionAddress, { commitment: 'processed' }); + assert(collection.name === "test"); + assert(collection.uri === "www.example.com"); + assert(collection.publicKey === collectionAddress); + assert(collection.numMinted === 0); + console.log(">>> Test Deploy Collection Passed"); +} + diff --git a/test/deployToken.ts b/test/deployToken.ts new file mode 100644 index 0000000..09c298b --- /dev/null +++ b/test/deployToken.ts @@ -0,0 +1,32 @@ +import { fetchDigitalAsset, mplTokenMetadata } from "@metaplex-foundation/mpl-token-metadata"; +import { SolanaAgentKit } from "../src"; +import { deploy_token } from "../src/tools"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { fromWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import assert from "assert"; + +export async function test_deploy_token() { + console.log("<<< Test Deploy Token"); + const solanaKit = new SolanaAgentKit( + process.env.SOLANA_PRIVATE_KEY!, + process.env.RPC_URL, + process.env.OPENAI_API_KEY! + ); + + const umi = createUmi(solanaKit.connection.rpcEndpoint).use(mplTokenMetadata()); + + const mint = fromWeb3JsPublicKey((await deploy_token(solanaKit, 6, "test", "www.example.com", "TEST")).mint); + + // Delay for 5 seconds + await new Promise(resolve => setTimeout(resolve, 5000)); + + const asset = await fetchDigitalAsset(umi, mint, { commitment: 'processed' }); + assert(asset.metadata.name === "test"); + assert(asset.metadata.uri === "www.example.com"); + assert(asset.metadata.symbol === 'TEST'); + assert(asset.metadata.sellerFeeBasisPoints === 0); + assert(asset.metadata.mint === mint); + assert(asset.metadata.sellerFeeBasisPoints === 0); + console.log(">>> Test Deploy Token Passed"); +} + diff --git a/test/mintNft.ts b/test/mintNft.ts new file mode 100644 index 0000000..3cd1377 --- /dev/null +++ b/test/mintNft.ts @@ -0,0 +1,42 @@ +import { SolanaAgentKit } from "../src"; +import { deploy_collection, mintCollectionNFT } from "../src/tools"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { fromWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters"; +import assert from "assert"; +import { fetchAsset, fetchCollection, mplCore } from "@metaplex-foundation/mpl-core"; + +export async function test_mint_nft() { + console.log("<<< Test Mint NFT"); + const solanaKit = new SolanaAgentKit( + process.env.SOLANA_PRIVATE_KEY!, + process.env.RPC_URL, + process.env.OPENAI_API_KEY! + ); + + const umi = createUmi(solanaKit.connection.rpcEndpoint).use(mplCore()); + + const { collectionAddress } = await deploy_collection(solanaKit, { + name: "test", + uri: "www.example.com", + }); + + const assetAddress = fromWeb3JsPublicKey(((await mintCollectionNFT(solanaKit, collectionAddress, { + name: "test", + uri: "www.example.com" + })).mint)); + + // Delay for 5 seconds + await new Promise(resolve => setTimeout(resolve, 5000)); + + const asset = await fetchAsset(umi, assetAddress, { commitment: 'processed' }); + assert(asset.name === "test"); + assert(asset.uri === "www.example.com"); + assert(asset.publicKey === assetAddress); + assert(asset.updateAuthority.address === fromWeb3JsPublicKey(collectionAddress)); + + const collection = await fetchCollection(umi, fromWeb3JsPublicKey(collectionAddress), { commitment: 'processed' }); + assert(collection.numMinted === 1); + + console.log(">>> Test Mint NFT Passed"); +} + diff --git a/test/tools.ts b/test/tools.ts new file mode 100644 index 0000000..d60cef5 --- /dev/null +++ b/test/tools.ts @@ -0,0 +1,29 @@ +import * as dotenv from "dotenv"; +import { test_deploy_token } from "./deployToken"; +import { test_deploy_collection } from "./deployCollection"; +import { test_mint_nft } from "./mintNft"; + +dotenv.config(); + +async function main() { + try { + console.log("Starting Agent..."); + + // Test Tools + await test_deploy_token(); + await test_deploy_collection(); + await test_mint_nft(); + } catch (error) { + if (error instanceof Error) { + console.error("Error:", error.message); + } + process.exit(1); + } +} + +if (require.main === module) { + main().catch(error => { + console.error("Fatal error:", error); + process.exit(1); + }); +} \ No newline at end of file