Skip to content

Commit 00f2f66

Browse files
authored
Feature/add spltoken2022 (#314)
# Pull Request Description ## Related Issue Feature Suggestion [#274](#274) ## Changes Made This PR adds the following changes: Add a function to create a token based on the SPL Token 2022 Program. The current implementation takes name, symbol, uri, decimal (optional), and initialSupply (optional) as parameters to create an SPL Token 2022. ## Implementation Details This PR includes the implementation of a basic SPL Token 2022 creation. Users can create a token based on the SPL Token 2022 library by providing name, symbol, uri, decimal (optional), and initialSupply (optional) as parameters. The basic implementation is similar to deployToken, but to implement the minting function based on initialSupply, I have added a method to obtain the PDA using findAssociatedTokenPda from the @metaplex-foundation/mpl-toolbox library. In the code that generates tokens using Metaplex, we used TOKEN_2022_PROGRAM_ID, which is defined as a constant in the @solana/spl-token library. To distinguish it from the standard deployToken, we explicitly added 2022 to the action in deployToken2022. ## Transaction executed by agent - [View Tranaction on Solscan](https://solscan.io/tx/iHt6MDYspeey64R7d53cC31E1crJ8QSqEUTaogXWz7yyHCJspP9wkqmBvdDHhMpYD3YzavnZdmLarF1cRdL9Xnp?cluster=devnet) ## Prompt Used ```typescript const userPrompt = ` Deploy SPL Token 2022 to Solana blockchain using Solana Agent Kit. Here is the required information: Token Name: "Test Token 2022" Token Symbol: "TEST22" Token Decimals: 9 Token URI: https://media1.giphy.com/media/l1KVboXQeiaX7FHgI/200.webp?cid=790b7611povvf63fxibbudqw20p4e8qfxs1dxunbk1qa3n89&ep=v1_gifs_search&rid=200.webp&ct=g Initial Supply: 1000000 After deploying the token 2022, provide the token address. `; ``` ## Checklist - [x] I have tested these changes locally - [x] I have updated the documentation - [x] I have added a transaction link - [x] I have added the prompt used to test it
2 parents 0e56b4c + 5527e1a commit 00f2f66

File tree

9 files changed

+265
-0
lines changed

9 files changed

+265
-0
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,27 @@ const result = await agent.deployToken(
151151
console.log("Token Mint Address:", result.mint.toString());
152152
```
153153

154+
### Deploy a New Token2022
155+
156+
```typescript
157+
const result = await agent.delpoyToken2022(
158+
"my ai token 2022", // name
159+
"uri", // uri
160+
"token2022", // symbol
161+
9, // decimals
162+
{
163+
mintAuthority: null, // by default, deployer account
164+
freezeAuthority: null, // by default, deployer account
165+
updateAuthority: undefined, // by default, deployer account
166+
isMutable: false // by default, true
167+
},
168+
1000000 // initial supply
169+
);
170+
171+
console.log("Token2022 Mint Address:", result.mint.toString());
172+
```
173+
174+
154175

155176
### Get all supported chains using Wormhole
156177
```typescript

src/actions/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import tokenBalancesAction from "./tokenBalances";
22
import deployTokenAction from "./metaplex/deployToken";
3+
import deployToken2022Action from "./metaplex/deployToken2022";
34
import balanceAction from "./solana/balance";
45
import transferAction from "./solana/transfer";
56
import deployCollectionAction from "./metaplex/deployCollection";
@@ -127,6 +128,7 @@ export const ACTIONS = {
127128
WALLET_ADDRESS_ACTION: getWalletAddressAction,
128129
TOKEN_BALANCES_ACTION: tokenBalancesAction,
129130
DEPLOY_TOKEN_ACTION: deployTokenAction,
131+
DEPLOY_TOKEN2022_ACTION: deployToken2022Action,
130132
BALANCE_ACTION: balanceAction,
131133
TRANSFER_ACTION: transferAction,
132134
DEPLOY_COLLECTION_ACTION: deployCollectionAction,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Action } from "../../types/action";
2+
import { SolanaAgentKit } from "../../agent";
3+
import { z } from "zod";
4+
import { deploy_token2022 } from "../../tools";
5+
6+
const deployToken2022Action: Action = {
7+
name: "DEPLOY_TOKEN_2022",
8+
similes: [
9+
"create token2022",
10+
"launch token2022",
11+
"deploy new token2022",
12+
"create new token2022",
13+
"mint token2022",
14+
],
15+
description:
16+
"Deploy a new SPL token2022 on the Solana blockchain with specified parameters",
17+
examples: [
18+
[
19+
{
20+
input: {
21+
name: "My Token",
22+
uri: "https://example.com/token.json",
23+
symbol: "MTK",
24+
decimals: 9,
25+
initialSupply: 1000000,
26+
},
27+
output: {
28+
mint: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
29+
status: "success",
30+
message: "Token deployed successfully",
31+
},
32+
explanation: "Deploy a token2022 with initial supply and metadata",
33+
},
34+
],
35+
[
36+
{
37+
input: {
38+
name: "Basic Token",
39+
uri: "https://example.com/basic.json",
40+
symbol: "BASIC",
41+
},
42+
output: {
43+
mint: "8nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkM",
44+
status: "success",
45+
message: "Token deployed successfully",
46+
},
47+
explanation: "Deploy a basic token2022 with minimal parameters",
48+
},
49+
],
50+
],
51+
schema: z.object({
52+
name: z.string().min(1, "Name is required"),
53+
uri: z.string().url("URI must be a valid URL"),
54+
symbol: z.string().min(1, "Symbol is required"),
55+
decimals: z.number().optional(),
56+
initialSupply: z.number().optional(),
57+
}),
58+
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
59+
try {
60+
const result = await deploy_token2022(
61+
agent,
62+
input.name,
63+
input.uri,
64+
input.symbol,
65+
input.decimals,
66+
input.initialSupply,
67+
);
68+
69+
return {
70+
mint: result.mint.toString(),
71+
status: "success",
72+
message: "Token deployed successfully",
73+
};
74+
} catch (error: any) {
75+
return {
76+
status: "error",
77+
message: `Token deployment failed: ${error.message}`,
78+
};
79+
}
80+
},
81+
};
82+
83+
export default deployToken2022Action;

src/agent/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { DEFAULT_OPTIONS } from "../constants";
1111
import {
1212
deploy_collection,
1313
deploy_token,
14+
deploy_token2022,
1415
get_balance,
1516
get_balance_other,
1617
getTPS,
@@ -276,6 +277,16 @@ export class SolanaAgentKit {
276277
);
277278
}
278279

280+
async deployToken2022(
281+
name: string,
282+
uri: string,
283+
symbol: string,
284+
decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS,
285+
initialSupply?: number,
286+
): Promise<{ mint: PublicKey }> {
287+
return deploy_token2022(this, name, uri, symbol, decimals, initialSupply);
288+
}
289+
279290
async deployCollection(
280291
options: CollectionOptions,
281292
): Promise<CollectionDeployment> {

src/langchain/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
SolanaBalanceOtherTool,
4545
SolanaTransferTool,
4646
SolanaDeployTokenTool,
47+
SolanaDeployToken2022Tool,
4748
SolanaDeployCollectionTool,
4849
SolanaMintNFTTool,
4950
SolanaTradeTool,
@@ -179,6 +180,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
179180
new SolanaBalanceOtherTool(solanaKit),
180181
new SolanaTransferTool(solanaKit),
181182
new SolanaDeployTokenTool(solanaKit),
183+
new SolanaDeployToken2022Tool(solanaKit),
182184
new SolanaDeployCollectionTool(solanaKit),
183185
new SolanaMintNFTTool(solanaKit),
184186
new SolanaTradeTool(solanaKit),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Tool } from "langchain/tools";
2+
import { SolanaAgentKit } from "../../agent";
3+
4+
export class SolanaDeployToken2022Tool extends Tool {
5+
name = "solana_deploy_token2022";
6+
description = `Deploy a new token2022 on Solana blockchain.
7+
8+
Inputs (input is a JSON string):
9+
name: string, eg "My Token" (required)
10+
uri: string, eg "https://example.com/token.json" (required)
11+
symbol: string, eg "MTK" (required)
12+
decimals?: number, eg 9 (optional, defaults to 9)
13+
initialSupply?: number, eg 1000000 (optional)`;
14+
15+
constructor(private solanaKit: SolanaAgentKit) {
16+
super();
17+
}
18+
19+
protected async _call(input: string): Promise<string> {
20+
try {
21+
const parsedInput = JSON.parse(input);
22+
23+
const result = await this.solanaKit.deployToken2022(
24+
parsedInput.name,
25+
parsedInput.uri,
26+
parsedInput.symbol,
27+
parsedInput.decimals,
28+
parsedInput.initialSupply,
29+
);
30+
31+
return JSON.stringify({
32+
status: "success",
33+
message: "Token2022 deployed successfully",
34+
mintAddress: result.mint.toString(),
35+
decimals: parsedInput.decimals || 9,
36+
});
37+
} catch (error: any) {
38+
return JSON.stringify({
39+
status: "error",
40+
message: error.message,
41+
code: error.code || "UNKNOWN_ERROR",
42+
});
43+
}
44+
}
45+
}

src/langchain/metaplex/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./deploy_collection";
22
export * from "./mint_nft";
33
export * from "./deploy_token";
4+
export * from "./deploy_token2022";
45
export * from "./get_asset";
56
export * from "./get_assets_by_authority";
67
export * from "./get_assets_by_creator";
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { SolanaAgentKit } from "../../index";
2+
import { PublicKey as LegacyPublicKey } from "@solana/web3.js";
3+
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
4+
import {
5+
generateSigner,
6+
keypairIdentity,
7+
publicKey,
8+
} from "@metaplex-foundation/umi";
9+
import {
10+
createFungible,
11+
mintV1,
12+
TokenStandard,
13+
} from "@metaplex-foundation/mpl-token-metadata";
14+
import {
15+
fromWeb3JsKeypair,
16+
fromWeb3JsPublicKey,
17+
toWeb3JsPublicKey,
18+
} from "@metaplex-foundation/umi-web3js-adapters";
19+
import {
20+
mplToolbox,
21+
findAssociatedTokenPda,
22+
} from "@metaplex-foundation/mpl-toolbox";
23+
import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
24+
import type { PublicKey } from "@metaplex-foundation/umi";
25+
26+
/**
27+
* Deploy a new SPL token
28+
* @param agent SolanaAgentKit instance
29+
* @param name Name of the token
30+
* @param uri URI for the token metadata
31+
* @param symbol Symbol of the token
32+
* @param decimals Number of decimals for the token (default: 9)
33+
* @param initialSupply Initial supply to mint (optional)
34+
* @returns Object containing token mint address and initial account (if supply was minted)
35+
*/
36+
37+
export async function deploy_token2022(
38+
agent: SolanaAgentKit,
39+
name: string,
40+
uri: string,
41+
symbol: string,
42+
decimals: number = 9,
43+
initialSupply?: number,
44+
): Promise<{ mint: LegacyPublicKey }> {
45+
try {
46+
// Create UMI instance from agent
47+
const umi = createUmi(agent.connection.rpcEndpoint).use(mplToolbox());
48+
umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet)));
49+
50+
const SPL_TOKEN_2022_PROGRAM_ID: PublicKey = publicKey(
51+
TOKEN_2022_PROGRAM_ID.toBase58(),
52+
);
53+
// Create new token2022 mint
54+
const mint = generateSigner(umi);
55+
56+
let builder = createFungible(umi, {
57+
name,
58+
uri,
59+
symbol,
60+
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
61+
sellerFeeBasisPoints: {
62+
basisPoints: 0n,
63+
identifier: "%",
64+
decimals: 2,
65+
},
66+
decimals,
67+
mint,
68+
});
69+
70+
if (initialSupply) {
71+
const token = findAssociatedTokenPda(umi, {
72+
mint: mint.publicKey,
73+
owner: fromWeb3JsPublicKey(agent.wallet_address),
74+
tokenProgramId: SPL_TOKEN_2022_PROGRAM_ID,
75+
});
76+
77+
builder = builder.add(
78+
mintV1(umi, {
79+
mint: mint.publicKey,
80+
token,
81+
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
82+
tokenStandard: TokenStandard.Fungible,
83+
tokenOwner: fromWeb3JsPublicKey(agent.wallet_address),
84+
amount: initialSupply * Math.pow(10, decimals),
85+
}),
86+
);
87+
}
88+
89+
await builder.sendAndConfirm(umi, {
90+
confirm: { commitment: "processed" },
91+
});
92+
93+
return {
94+
mint: toWeb3JsPublicKey(mint.publicKey),
95+
};
96+
} catch (error: any) {
97+
throw new Error(`Token deployment failed: ${error.message}`);
98+
}
99+
}

src/tools/metaplex/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./deploy_collection";
22
export * from "./mint_nft";
33
export * from "./deploy_token";
4+
export * from "./deploy_token2022";
45
export * from "./get_asset";
56
export * from "./get_assets_by_authority";
67
export * from "./get_assets_by_creator";

0 commit comments

Comments
 (0)