Adding basic tests and fixing issues.

This commit is contained in:
Blockiosaurus
2024-12-18 21:52:22 -05:00
4 changed files with 1444 additions and 1255 deletions

2514
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -53,13 +53,13 @@ export class SolanaAgentKit {
}
async deployToken(
decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS,
name: string,
uri: string,
symbol: string,
decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS,
initialSupply?: number,
) {
return deploy_token(this, decimals, name, uri, symbol, initialSupply);
return deploy_token(this, name, uri, symbol, decimals, initialSupply);
}
async deployCollection(options: CollectionOptions) {

View File

@@ -64,7 +64,7 @@ export class SolanaTransferTool extends Tool {
const tx = await this.solanaKit.transfer(
recipient,
parsedInput.amount,
mintAddress,
mintAddress
);
return JSON.stringify({
@@ -87,38 +87,32 @@ 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, name: string, uri: string, symbol: string, initialSupply?: number}";
description = `Deploy a new token on Solana blockchain.
Inputs (input is a JSON string):
name: string, eg "My Token" (required)
uri: string, eg "https://example.com/token.json" (required)
symbol: string, eg "MTK" (required)
decimals?: number, eg 9 (optional, defaults to 9)
initialSupply?: number, eg 1000000 (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
private validateInput(input: any): void {
if (
input.decimals !== undefined &&
(typeof input.decimals !== "number" ||
input.decimals < 0 ||
input.decimals > 9)
) {
throw new Error(
"decimals must be a number between 0 and 9 when provided",
);
}
if (
input.initialSupply !== undefined &&
(typeof input.initialSupply !== "number" || input.initialSupply <= 0)
) {
throw new Error("initialSupply must be a positive number when provided");
}
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = toJSON(input);
this.validateInput(parsedInput);
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.deployToken(parsedInput.decimals, parsedInput.name, parsedInput.uri, parsedInput.symbol, parsedInput.initialSupply);
console.log(parsedInput);
const result = await this.solanaKit.deployToken(
parsedInput.name,
parsedInput.uri,
parsedInput.symbol,
parsedInput.decimals,
parsedInput.initialSupply
);
return JSON.stringify({
status: "success",
@@ -138,57 +132,21 @@ export class SolanaDeployTokenTool extends Tool {
export class SolanaDeployCollectionTool extends Tool {
name = "solana_deploy_collection";
description =
"Deploy a new NFT collection. Input should be JSON with: {name: string, uri: string, royaltyBasisPoints?: number, creators?: Array<{address: string, percentage: number}>}";
description = `Deploy a new NFT collection on Solana blockchain.
Inputs (input is a JSON string):
name: string, eg "My Collection" (required)
uri: string, eg "https://example.com/collection.json" (required)
royaltyBasisPoints?: number, eg 500 for 5% (optional)
creators?: Array<{address: string, percentage: number}>, eg [{address: "abc123...", percentage: 100}] (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
private validateInput(input: any): void {
if (!input.name || typeof input.name !== "string") {
throw new Error("name is required and must be a string");
}
if (!input.uri || typeof input.uri !== "string") {
throw new Error("uri is required and must be a string");
}
if (
input.royaltyBasisPoints !== undefined &&
(typeof input.royaltyBasisPoints !== "number" ||
input.royaltyBasisPoints < 0 ||
input.royaltyBasisPoints > 10000)
) {
throw new Error(
"royaltyBasisPoints must be a number between 0 and 10000 when provided",
);
}
if (input.creators) {
if (!Array.isArray(input.creators)) {
throw new Error("creators must be an array when provided");
}
input.creators.forEach((creator: any, index: number) => {
if (!creator.address || typeof creator.address !== "string") {
throw new Error(
`creator[${index}].address is required and must be a string`,
);
}
if (
typeof creator.percentage !== "number" ||
creator.percentage < 0 ||
creator.percentage > 100
) {
throw new Error(
`creator[${index}].percentage must be a number between 0 and 100`,
);
}
});
}
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = toJSON(input);
this.validateInput(parsedInput);
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.deployCollection(parsedInput);
@@ -210,52 +168,42 @@ export class SolanaDeployCollectionTool extends Tool {
export class SolanaMintNFTTool extends Tool {
name = "solana_mint_nft";
description =
"Mint a new NFT in a collection. Input should be JSON with: {collectionMint: string, metadata: {name: string, symbol: string, uri: string}, recipient?: string}";
description = `Mint a new NFT in a collection on Solana blockchain.
Inputs (input is a JSON string):
collectionMint: string, eg "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" (required) - The address of the collection to mint into
name: string, eg "My NFT" (required)
symbol: string, eg "NFT" (required)
uri: string, eg "https://example.com/nft.json" (required)
recipient?: string, eg "9aUn5swQzUTRanaaTwmszxiv89cvFwUCjEBv1vZCoT1u" (optional) - The wallet to receive the NFT, defaults to agent's wallet`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
private validateInput(input: any): void {
if (!input.collectionMint || typeof input.collectionMint !== "string") {
throw new Error("collectionMint is required and must be a string");
}
if (!input.metadata || typeof input.metadata !== "object") {
throw new Error("metadata is required and must be an object");
}
if (!input.metadata.name || typeof input.metadata.name !== "string") {
throw new Error("metadata.name is required and must be a string");
}
if (!input.metadata.symbol || typeof input.metadata.symbol !== "string") {
throw new Error("metadata.symbol is required and must be a string");
}
if (!input.metadata.uri || typeof input.metadata.uri !== "string") {
throw new Error("metadata.uri is required and must be a string");
}
if (input.recipient !== undefined && typeof input.recipient !== "string") {
throw new Error("recipient must be a string when provided");
}
}
protected async _call(input: string): Promise<string> {
try {
const parsedInput = toJSON(input);
this.validateInput(parsedInput);
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.mintNFT(
new PublicKey(parsedInput.collectionMint),
parsedInput.metadata,
parsedInput.recipient
? new PublicKey(parsedInput.recipient)
: undefined,
{
name: parsedInput.name,
symbol: parsedInput.symbol,
uri: parsedInput.uri,
},
parsedInput.recipient ? new PublicKey(parsedInput.recipient) : undefined
);
return JSON.stringify({
status: "success",
message: "NFT minted successfully",
mintAddress: result.mint.toString(),
name: parsedInput.metadata.name,
metadata: {
name: parsedInput.name,
symbol: parsedInput.symbol,
uri: parsedInput.uri,
},
recipient: parsedInput.recipient || result.mint.toString(),
});
} catch (error: any) {
@@ -292,7 +240,7 @@ export class SolanaTradeTool extends Tool {
parsedInput.inputMint
? new PublicKey(parsedInput.inputMint)
: new PublicKey("So11111111111111111111111111111111111111112"),
parsedInput.slippageBps,
parsedInput.slippageBps
);
return JSON.stringify({
@@ -372,7 +320,7 @@ export class SolanaRegisterDomainTool extends Tool {
const tx = await this.solanaKit.registerDomain(
parsedInput.name,
parsedInput.spaceKB || 1,
parsedInput.spaceKB || 1
);
return JSON.stringify({
@@ -424,7 +372,6 @@ export class SolanaResolveDomainTool extends Tool {
}
}
export class SolanaGetDomainTool extends Tool {
name = "solana_get_domain";
description = `Retrieve the .sol domain associated for a given account address.
@@ -437,7 +384,6 @@ export class SolanaGetDomainTool extends Tool {
super();
}
protected async _call(input: string): Promise<string> {
try {
const account = new PublicKey(input.trim());
@@ -529,7 +475,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
telegram: parsedInput.telegram,
website: parsedInput.website,
initialLiquiditySOL: parsedInput.initialLiquiditySOL,
},
}
);
return JSON.stringify({
@@ -714,9 +660,7 @@ export class SolanaTokenDataTool extends Tool {
try {
const parsedInput = input.trim();
const tokenData = await this.solanaKit.getTokenDataByAddress(
parsedInput
);
const tokenData = await this.solanaKit.getTokenDataByAddress(parsedInput);
return JSON.stringify({
status: "success",

View File

@@ -17,11 +17,11 @@ import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@meta
*/
export async function deploy_token(
agent: SolanaAgentKit,
decimals: number = 9,
name: string,
uri: string,
symbol: string,
initialSupply?: number,
decimals: number = 9,
initialSupply?: number
): Promise<{ mint: PublicKey }> {
try {
// Create UMI instance from agent
@@ -31,16 +31,13 @@ export async function deploy_token(
// Create new token mint
const mint = generateSigner(umi);
console.log("Mint address: ", mint.publicKey.toString());
console.log("Agent address: ", agent.wallet_address.toString());
let builder = createFungible(umi, {
name,
uri,
symbol,
sellerFeeBasisPoints: {
basisPoints: 0n,
identifier: '%',
identifier: "%",
decimals: 2,
},
decimals,
@@ -48,12 +45,14 @@ export async function deploy_token(
});
if (initialSupply) {
builder = builder.add(mintV1(umi, {
mint: mint.publicKey,
tokenStandard: TokenStandard.Fungible,
tokenOwner: fromWeb3JsPublicKey(agent.wallet_address),
amount: initialSupply,
}));
builder = builder.add(
mintV1(umi, {
mint: mint.publicKey,
tokenStandard: TokenStandard.Fungible,
tokenOwner: fromWeb3JsPublicKey(agent.wallet_address),
amount: initialSupply,
})
);
}
builder.sendAndConfirm(umi, { confirm: { commitment: 'finalized' } });