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

fix create fungible decimals and optionally create ata #313

Merged
merged 1 commit into from
Dec 23, 2023
Merged
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
13 changes: 12 additions & 1 deletion src/create/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use solana_sdk::signature::read_keypair_file;
use spl_associated_token_account::get_associated_token_address;
use spl_token::instruction::mint_to;

use crate::utils::create_token_if_missing_instruction;

use super::*;

pub struct CreateMetadataArgs {
Expand Down Expand Up @@ -127,7 +129,7 @@ pub fn create_fungible(args: CreateFungibleArgs) -> Result<()> {
collection: None,
uses: None,
collection_details: None,
decimals: None,
decimals: Some(args.decimals),
rule_set: None,
print_supply: None,
};
Expand All @@ -150,6 +152,15 @@ pub fn create_fungible(args: CreateFungibleArgs) -> Result<()> {
// Derive associated token account
let assoc = get_associated_token_address(&keypair.pubkey(), &mint.pubkey());

// Create associated token account if needed
instructions.push(create_token_if_missing_instruction(
&keypair.pubkey(),
&assoc,
&mint.pubkey(),
&keypair.pubkey(),
&assoc,
));

// Mint to instruction
let mint_to_ix = mint_to(
&spl_token::ID,
Expand Down
54 changes: 53 additions & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use anyhow::{anyhow, Result};
use borsh::{BorshDeserialize, BorshSerialize};
use retry::{delay::Exponential, retry};
use serde::Deserialize;
use serde_json::json;
use solana_client::rpc_request::RpcRequest;
use solana_client::{nonblocking::rpc_client::RpcClient as AsyncRpcClient, rpc_client::RpcClient};
use solana_program::instruction::AccountMeta;
use solana_program::program_pack::Pack;
use solana_program::pubkey::Pubkey;
use solana_program::system_program;
use solana_program::{pubkey, pubkey::Pubkey};
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::{
instruction::Instruction, signature::Keypair, signer::Signer, transaction::Transaction,
Expand Down Expand Up @@ -300,3 +303,52 @@ struct TokenAccount {
// #[serde(rename = "uiAmountString")]
// ui_amount_string: String,
}

const MPL_TOOLBOX_ID: Pubkey = pubkey!("TokExjvjJmhKaRBShsBAsbSvEWMA1AgUNK7ps4SAc2p");

#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)]
#[rustfmt::skip]
pub enum TokenExtrasInstruction {
/// Creates a new associated token account for the given mint and owner, if and only if
/// the given token account does not exists and the token account is the same as the
/// associated token account. That way, clients can ensure that, after this instruction,
/// the token account will exists.
///
/// Notice this instruction asks for both the token account and the associated token account (ATA)
/// These may or may not be the same account. Here are all the possible cases:
///
/// - Token exists and Token is ATA: Instruction succeeds.
/// - Token exists and Token is not ATA: Instruction succeeds.
/// - Token does not exist and Token is ATA: Instruction creates the ATA account and succeeds.
/// - Token does not exist and Token is not ATA: Instruction fails as we cannot create a
/// non-ATA account without it being a signer.
///
/// Note that additional checks are made to ensure that the token account provided
/// matches the mint account and owner account provided.
CreateTokenIfMissing,
}

pub fn create_token_if_missing_instruction(
payer: &Pubkey,
token: &Pubkey,
mint: &Pubkey,
owner: &Pubkey,
ata: &Pubkey,
) -> Instruction {
Instruction {
program_id: MPL_TOOLBOX_ID,
accounts: vec![
AccountMeta::new(*payer, true),
AccountMeta::new_readonly(*token, false),
AccountMeta::new_readonly(*mint, false),
AccountMeta::new_readonly(*owner, false),
AccountMeta::new(*ata, false),
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new_readonly(spl_associated_token_account::id(), false),
],
data: TokenExtrasInstruction::CreateTokenIfMissing
.try_to_vec()
.unwrap(),
}
}
Loading