solagent_plugin_solana/
deploy_token.rs

1// Copyright 2025 zTgx
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::DeployedData;
16use mpl_token_metadata::{
17    accounts::Metadata,
18    instructions::{CreateV1, CreateV1InstructionArgs},
19    types::{PrintSupply, TokenStandard},
20};
21use solagent_core::{
22    solana_client::{client_error::ClientError, rpc_config::RpcSendTransactionConfig},
23    solana_program,
24    solana_sdk::{
25        program_pack::Pack,
26        signature::{Keypair, Signer},
27        system_instruction, system_program,
28        {commitment_config::CommitmentConfig, transaction::Transaction},
29    },
30    SolanaAgentKit,
31};
32use spl_associated_token_account::get_associated_token_address;
33use spl_token::instruction as spl_token_instruction;
34
35/// Deploys a new SPL token.
36///
37/// # Parameters
38///
39/// - `agent`: An instance of `SolanaAgentKit`.
40/// - `name`: Name of the token.
41/// - `uri`: URI for the token metadata.
42/// - `symbol`: Symbol of the token.
43/// - `decimals`: Number of decimals for the token (default: 9).
44/// - `initial_supply`: Initial supply to mint (optional).
45///
46/// # Returns
47///
48/// An object containing the token mint address.
49pub async fn deploy_token(
50    agent: &SolanaAgentKit,
51    name: String,
52    uri: String,
53    symbol: String,
54    decimals: u8,
55    initial_supply: Option<u64>,
56) -> Result<DeployedData, ClientError> {
57    let mint = Keypair::new();
58    let mint_pubkey = mint.pubkey();
59
60    // Create token mint account
61    let min_rent = agent
62        .connection
63        .get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?;
64
65    let create_mint_account_ix = system_instruction::create_account(
66        &agent.wallet.pubkey,
67        &mint_pubkey,
68        min_rent,
69        spl_token::state::Mint::LEN as u64,
70        &spl_token::id(),
71    );
72
73    let initialize_mint_ix = spl_token_instruction::initialize_mint(
74        &spl_token::id(),
75        &mint_pubkey,
76        &agent.wallet.pubkey,
77        Some(&agent.wallet.pubkey),
78        decimals,
79    )
80    .expect("initialize_mint");
81
82    // Create metadata account
83    let (metadata, _x) = Metadata::find_pda(&mint_pubkey);
84    // instruction args
85    let args = CreateV1InstructionArgs {
86        name,
87        symbol,
88        uri,
89        seller_fee_basis_points: 500,
90        primary_sale_happened: false,
91        is_mutable: true,
92        token_standard: TokenStandard::Fungible,
93        collection: None,
94        uses: None,
95        collection_details: None,
96        creators: None,
97        rule_set: None,
98        decimals: Some(18),
99        print_supply: Some(PrintSupply::Zero),
100    };
101
102    // instruction accounts
103    let create_ix = CreateV1 {
104        metadata,
105        master_edition: None,
106        mint: (mint_pubkey, true),
107        authority: agent.wallet.pubkey,
108        payer: agent.wallet.pubkey,
109        update_authority: (agent.wallet.pubkey, true),
110        system_program: system_program::ID,
111        sysvar_instructions: solana_program::sysvar::instructions::ID,
112        spl_token_program: Some(spl_token::ID),
113    };
114    let create_metadata_ix = create_ix.instruction(args);
115
116    let mut instructions = vec![
117        create_mint_account_ix,
118        initialize_mint_ix,
119        create_metadata_ix,
120    ];
121
122    if let Some(supply) = initial_supply {
123        let associated_token_account =
124            get_associated_token_address(&agent.wallet.pubkey, &mint_pubkey);
125
126        let create_associated_token_account_ix =
127            spl_associated_token_account::instruction::create_associated_token_account(
128                &agent.wallet.pubkey,
129                &agent.wallet.pubkey,
130                &mint_pubkey,
131                &spl_token::id(),
132            );
133
134        let mint_to_ix = spl_token_instruction::mint_to(
135            &spl_token::id(),
136            &mint_pubkey,
137            &associated_token_account,
138            &agent.wallet.pubkey,
139            &[&agent.wallet.pubkey],
140            supply,
141        )
142        .expect("mint_to");
143
144        instructions.push(create_associated_token_account_ix);
145        instructions.push(mint_to_ix);
146    }
147
148    let recent_blockhash = agent.connection.get_latest_blockhash()?;
149    let transaction = Transaction::new_signed_with_payer(
150        &instructions,
151        Some(&agent.wallet.pubkey),
152        &[&agent.wallet.keypair, &mint],
153        recent_blockhash,
154    );
155
156    let signature = agent
157        .connection
158        .send_and_confirm_transaction_with_spinner_and_config(
159            &transaction,
160            CommitmentConfig::finalized(),
161            RpcSendTransactionConfig {
162                skip_preflight: true,
163                ..Default::default()
164            },
165        )?;
166
167    Ok(DeployedData::new(
168        mint_pubkey.to_string(),
169        signature.to_string(),
170    ))
171}