Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add tool to create non transferable token mint #236

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@pythnetwork/hermes-client": "^1.3.0",
"@raydium-io/raydium-sdk-v2": "0.1.95-alpha",
"@solana/spl-token": "^0.4.9",
"@solana/spl-token-metadata": "^0.1.6",
"@solana/web3.js": "^1.98.0",
"@sqds/multisig": "^2.1.3",
"@tensor-oss/tensorswap-sdk": "^4.5.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ import getAssetAction from "./metaplex/getAsset";
import getAssetsByAuthorityAction from "./metaplex/getAssetsByAuthority";
import getAssetsByCreatorAction from "./metaplex/getAssetsByCreator";
import getInfoAction from "./agent/get_info";
import createNonTransferableMintAction from "./solana/token2022/create_non_transferable_token_mint";
import mintToken2022Action from "./solana/token2022/mint_token2022";
import getPriceInferenceAction from "./allora/getPriceInference";
import getAllTopicsAction from "./allora/getAllTopics";
import getInferenceByTopicIdAction from "./allora/getInferenceByTopicId";
Expand Down Expand Up @@ -160,6 +162,8 @@ export const ACTIONS = {
GET_ASSET_ACTION: getAssetAction,
GET_ASSETS_BY_AUTHORITY_ACTION: getAssetsByAuthorityAction,
GET_ASSETS_BY_CREATOR_ACTION: getAssetsByCreatorAction,
CREATE_NON_TRANSFERABLE_MINT_ACTION: createNonTransferableMintAction,
MINT_TOKEN_2022_ACTION: mintToken2022Action,
GET_PRICE_INFERENCE_ACTION: getPriceInferenceAction,
GET_ALL_TOPICS_ACTION: getAllTopicsAction,
GET_INFERENCE_BY_TOPIC_ID_ACTION: getInferenceByTopicIdAction,
Expand Down
72 changes: 72 additions & 0 deletions src/actions/solana/token2022/create_non_transferable_token_mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Action } from "../../../types/action";
import { SolanaAgentKit } from "../../../agent";
import { z } from "zod";
import { createNonTransferableTokenMint } from "../../../tools";

const createNonTransferableMintAction: Action = {
name: "CREATE_NON_TRANSFERABLE_MINT",
similes: [
"create non-transferable token",
"create non transferable NFT",
"initialize non-transferable mint",
"mint non-transferable tokens",
],
description: `Create a non-transferable token mint with specified decimals and metadata.`,
examples: [
[
{
input: {
decimals: 9,
tokenName: "My Non-Transferable Token",
tokenSymbol: "MNT",
uri: "https://example.com/token-metadata",
additionalMetadata: [["customField1", "customValue1"]],
},
output: {
status: "success",
message: "Non-transferable mint created successfully",
mint: "8z1FnrcutaAmNZ57wbAb6fqNNBcTiMQWRZQb3sg8cYkv",
transaction:
"2Skosa48ky13c2qC6fqAPbNLDP29hUk16J9BTKhs32mgoeLSZKudSyexywacQfRXvq4Hj8WFUX1bcQWtSYa7sW2n",
},
explanation:
"Create a non-transferable token mint with 9 decimals and metadata",
},
],
],
schema: z.object({
decimals: z
.number()
.int()
.nonnegative("Decimals must be a non-negative integer"),
tokenName: z.string().min(1, "Token name is required"),
tokenSymbol: z.string().min(1, "Token symbol is required"),
uri: z.string().url("URI must be a valid URL"),
additionalMetadata: z.array(z.tuple([z.string(), z.string()])).optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const decimals = input.decimals;
const tokenName = input.tokenName;
const tokenSymbol = input.tokenSymbol;
const uri = input.uri;
const additionalMetadata = input.additionalMetadata || [];

const { mint, signature } = await createNonTransferableTokenMint(
agent,
decimals,
tokenName,
tokenSymbol,
uri,
additionalMetadata,
);

return {
status: "success",
message: "Non-transferable mint created successfully",
mint: mint.toString(),
transaction: signature,
};
},
};

export default createNonTransferableMintAction;
92 changes: 92 additions & 0 deletions src/actions/solana/token2022/mint_token2022.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { PublicKey } from "@solana/web3.js";
import { Action } from "../../../types/action";
import { SolanaAgentKit } from "../../../agent";
import { z } from "zod";
import { mint_token2022 } from "../../../tools";

const mintToken2022Action: Action = {
name: "MINT_TOKEN_2022",
similes: [
"mint new tokens",
"create tokens",
"issue tokens",
"generate tokens",
],
description: `Mint a Token 2022 to a specified destination address.`,
examples: [
[
{
input: {
mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
destination: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
decimals: 6,
amount: 100,
},
output: {
status: "success",
message: "Minting completed successfully",
amount: 100,
recipient: "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk",
token: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
transaction:
"5UfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
},
explanation: "Mint 100 tokens to the recipient address",
},
],
[
{
input: {
mint: "8z1FnrcutaAmNZ57wbAb6fqNNBcTiMQWRZQb3sg8cYkv",
destination: "EXBdeRCdiNChKyD7akt64n9HgSXEpUtpPEhmbnm4L6iH",
decimals: 9,
amount: 1,
},
output: {
status: "success",
message: "Minting completed successfully",
amount: 1,
recipient: "EXBdeRCdiNChKyD7akt64n9HgSXEpUtpPEhmbnm4L6iH",
token: "8z1FnrcutaAmNZ57wbAb6fqNNBcTiMQWRZQb3sg8cYkv",
transaction:
"3UfgJ5vVZxUxefDGqzqkVLHzHxVTyYH9StYyHKgvHYmXJgqJKxEqy9k4Rz9LpXrHF9kUZB7",
},
explanation: "Mint 1 token to the recipient address with 9 decimals",
},
],
],
schema: z.object({
mint: z.string().min(32, "Invalid mint address"),
destination: z.string().min(32, "Invalid destination address"),
decimals: z
.number()
.int()
.nonnegative("Decimals must be a non-negative integer"),
amount: z.number().positive("Amount must be positive").optional(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const mintAddress = new PublicKey(input.mint);
const destinationAddress = new PublicKey(input.destination);
const decimals = input.decimals;
const amount = input.amount || 1;

const tx = await mint_token2022(
agent,
mintAddress,
destinationAddress,
decimals,
amount,
);

return {
status: "success",
message: "Minting completed successfully",
amount: amount,
recipient: input.destination,
token: input.mint,
transaction: tx,
};
},
};

export default mintToken2022Action;
28 changes: 28 additions & 0 deletions src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@
get_asset,
get_assets_by_authority,
get_assets_by_creator,
createNonTransferableTokenMint,
mint_token2022,
getPriceInference,
getAllTopics,
getInferenceByTopicId,
Expand All @@ -142,7 +144,7 @@
DasApiAssetList,
GetAssetsByAuthorityRpcInput,
GetAssetsByCreatorRpcInput,
SearchAssetsRpcInput,

Check warning on line 147 in src/agent/index.ts

View workflow job for this annotation

GitHub Actions / check

'SearchAssetsRpcInput' is defined but never used
} from "@metaplex-foundation/digital-asset-standard-api";
import { AlloraInference, AlloraTopic } from "@alloralabs/allora-sdk";

Expand Down Expand Up @@ -1033,6 +1035,32 @@
): Promise<DasApiAssetList> {
return get_assets_by_creator(this, params);
}

async createNonTransferableTokenMint(
decimals: number,
tokenName: string,
tokenSymbol: string,
uri: string,
additionalMetadata?: [string, string][],
): Promise<{ mint: PublicKey; signature: string }> {
return createNonTransferableTokenMint(
this,
decimals,
tokenName,
tokenSymbol,
uri,
additionalMetadata,
);
}

async mint_token2022(
mint: PublicKey,
destination: PublicKey,
decimals: number,
amount?: number,
) {
return mint_token2022(this, mint, destination, decimals, amount);
}
async getPriceInference(
tokenSymbol: string,
timeframe: string,
Expand Down
6 changes: 6 additions & 0 deletions src/langchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ import {
SolanaAlloraGetAllTopics,
SolanaAlloraGetInferenceByTopicId,
} from "./index";
import {
SolanaCreateNonTransferableTokenMintTool,
SolanaMintToken2022Tool,
} from "./solana";

export function createSolanaTools(solanaKit: SolanaAgentKit) {
return [
Expand Down Expand Up @@ -250,6 +254,8 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaGetAssetTool(solanaKit),
new SolanaGetAssetsByAuthorityTool(solanaKit),
new SolanaGetAssetsByCreatorTool(solanaKit),
new SolanaCreateNonTransferableTokenMintTool(solanaKit),
new SolanaMintToken2022Tool(solanaKit),
new SolanaAlloraGetPriceInference(solanaKit),
new SolanaAlloraGetAllTopics(solanaKit),
new SolanaAlloraGetInferenceByTopicId(solanaKit),
Expand Down
1 change: 1 addition & 0 deletions src/langchain/solana/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./balance";
export * from "./balance_other";
export * from "./close_empty_accounts";
export * from "./transfer";
export * from "./token2022/index";
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../../../agent";

export class SolanaCreateNonTransferableTokenMintTool extends Tool {
name = "solana_create_non_transferable_token_mint";
description = `Create a non-transferable token mint.

Inputs (input is a JSON string):
{
"decimals": number, // e.g., 9
"tokenName": string, // e.g., "My Non-Transferable Token"
"tokenSymbol": string, // e.g., "MNT"
"uri": string, // e.g., "https://example.com/token-metadata"
"additionalMetadata": [["customField", "customValue"]] // optional
}`;

constructor(private solanaKit: SolanaAgentKit) {
super();
}

protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);

const { mint, signature } =
await this.solanaKit.createNonTransferableTokenMint(
parsedInput.decimals,
parsedInput.tokenName,
parsedInput.tokenSymbol,
parsedInput.uri,
parsedInput.additionalMetadata || [],
);

return JSON.stringify({
status: "success",
mint: mint.toString(),
signature,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
2 changes: 2 additions & 0 deletions src/langchain/solana/token2022/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./mint_token2022";
export * from "./create_nontransferable_token_mint";
45 changes: 45 additions & 0 deletions src/langchain/solana/token2022/mint_token2022.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../../../agent";
import { PublicKey } from "@solana/web3.js";

export class SolanaMintToken2022Tool extends Tool {
name = "solana_mint_token2022";
description = `mint a token(token2022) to a destination address

Inputs ( input is a JSON string ):
mint: string, eg 8z1FnrcutaAmNZ57wbAb6fqNNBcTiMQWRZQb3sg8cYkv,
destination: string eg EXBdeRCdiNChKyD7akt64n9HgSXEpUtpPEhmbnm4L6iH,
decimals: number, eg 9
amount: number eg 2 (optional)
`;

constructor(private solanaKit: SolanaAgentKit) {
super();
}

protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);

const mint = new PublicKey(parsedInput.mint);
const destination = new PublicKey(parsedInput.destination);

const tx = await this.solanaKit.mint_token2022(
mint,
destination,
parsedInput.decimals,
parsedInput.amount,
);
return JSON.stringify({
status: "success",
tx,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
1 change: 1 addition & 0 deletions src/tools/solana/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from "./transfer";
export * from "./get_balance";
export * from "./get_balance_other";
export * from "./get_token_balances";
export * from "./token2022/index";
Loading
Loading