jpcaulfi 2 yıl önce
ebeveyn
işleme
c1ad867427
25 değiştirilmiş dosya ile 852 ekleme ve 2 silme
  1. 2 1
      tokens/create-token/anchor/programs/create-token/src/lib.rs
  2. 2 1
      tokens/create-token/native/program/src/lib.rs
  3. 1 0
      tokens/spl-token-minter/README.md
  4. 14 0
      tokens/spl-token-minter/anchor/Anchor.toml
  5. 13 0
      tokens/spl-token-minter/anchor/Cargo.toml
  6. 15 0
      tokens/spl-token-minter/anchor/package.json
  7. 21 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/Cargo.toml
  8. 2 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/Xargo.toml
  9. 75 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/create.rs
  10. 58 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mint.rs
  11. 5 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mod.rs
  12. 40 0
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/lib.rs
  13. 81 0
      tokens/spl-token-minter/anchor/tests/test.ts
  14. 10 0
      tokens/spl-token-minter/anchor/tsconfig.json
  15. 8 0
      tokens/spl-token-minter/native/cicd.sh
  16. 22 0
      tokens/spl-token-minter/native/package.json
  17. 15 0
      tokens/spl-token-minter/native/program/Cargo.toml
  18. 125 0
      tokens/spl-token-minter/native/program/src/instructions/create.rs
  19. 86 0
      tokens/spl-token-minter/native/program/src/instructions/mint.rs
  20. 5 0
      tokens/spl-token-minter/native/program/src/instructions/mod.rs
  21. 22 0
      tokens/spl-token-minter/native/program/src/lib.rs
  22. 44 0
      tokens/spl-token-minter/native/program/src/processor.rs
  23. 51 0
      tokens/spl-token-minter/native/tests/instructions.ts
  24. 125 0
      tokens/spl-token-minter/native/tests/test.ts
  25. 10 0
      tokens/spl-token-minter/native/tsconfig.json

+ 2 - 1
tokens/create-token/anchor/programs/create-token/src/lib.rs

@@ -26,7 +26,7 @@ pub mod create_token {
         msg!("Creating metadata account...");
         msg!("Metadata account address: {}", &ctx.accounts.metadata_account.key());
         invoke(
-            &mpl_instruction::create_metadata_accounts_v2(
+            &mpl_instruction::create_metadata_accounts_v3(
                 ctx.accounts.token_metadata_program.key(),      // Program ID (the Token Metadata Program)
                 ctx.accounts.metadata_account.key(),            // Metadata account
                 ctx.accounts.mint_account.key(),                // Mint account
@@ -42,6 +42,7 @@ pub mod create_token {
                 false,                                          // Is mutable
                 None,                                           // Collection
                 None,                                           // Uses
+                None,                                           // Collection Details
             ),
             &[
                 ctx.accounts.metadata_account.to_account_info(),

+ 2 - 1
tokens/create-token/native/program/src/lib.rs

@@ -101,7 +101,7 @@ fn process_instruction(
     msg!("Creating metadata account...");
     msg!("Metadata account address: {}", metadata_account.key);
     invoke(
-        &mpl_instruction::create_metadata_accounts_v2(
+        &mpl_instruction::create_metadata_accounts_v3(
             *token_metadata_program.key,
             *metadata_account.key,
             *mint_account.key,
@@ -117,6 +117,7 @@ fn process_instruction(
             false,
             None,
             None,
+            None,
         ),
         &[
             metadata_account.clone(),

+ 1 - 0
tokens/spl-token-minter/README.md

@@ -0,0 +1 @@
+# SPL Token Minter

+ 14 - 0
tokens/spl-token-minter/anchor/Anchor.toml

@@ -0,0 +1,14 @@
+[features]
+seeds = false
+[programs.devnet]
+spl_token_minter = "5BStrknWEiQWHmDGdDBaG7j9qegfN2Nq83M3hXajjgXY"
+
+[registry]
+url = "https://anchor.projectserum.com"
+
+[provider]
+cluster = "devnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 13 - 0
tokens/spl-token-minter/anchor/Cargo.toml

@@ -0,0 +1,13 @@
+[workspace]
+members = [
+    "programs/*"
+]
+
+[profile.release]
+overflow-checks = true
+lto = "fat"
+codegen-units = 1
+[profile.release.build-override]
+opt-level = 3
+incremental = false
+codegen-units = 1

+ 15 - 0
tokens/spl-token-minter/anchor/package.json

@@ -0,0 +1,15 @@
+{
+    "dependencies": {
+        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+        "@project-serum/anchor": "^0.24.2"
+    },
+    "devDependencies": {
+        "@types/bn.js": "^5.1.0",
+        "@types/chai": "^4.3.0",
+        "@types/mocha": "^9.0.0",
+        "chai": "^4.3.4",
+        "mocha": "^9.0.3",
+        "ts-mocha": "^10.0.0",
+        "typescript": "^4.3.5"
+    }
+}

+ 21 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/Cargo.toml

@@ -0,0 +1,21 @@
+[package]
+name = "spl-token-minter"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "spl_token_minter"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = "0.25.0"
+anchor-spl = "0.25.0"
+mpl-token-metadata = { version="1.2.5", features = [ "no-entrypoint" ] }

+ 2 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 75 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/create.rs

@@ -0,0 +1,75 @@
+use {
+    anchor_lang::{
+        prelude::*,
+        solana_program::program::invoke,
+    },
+    anchor_spl::token,
+    mpl_token_metadata::instruction as mpl_instruction,
+};
+
+
+pub fn create_token(
+    ctx: Context<CreateToken>, 
+    token_title: String, 
+    token_symbol: String, 
+    token_uri: String,
+) -> Result<()> {
+
+    msg!("Creating metadata account...");
+    msg!("Metadata account address: {}", &ctx.accounts.metadata_account.key());
+    invoke(
+        &mpl_instruction::create_metadata_accounts_v3(
+            ctx.accounts.token_metadata_program.key(),      // Program ID (the Token Metadata Program)
+            ctx.accounts.metadata_account.key(),            // Metadata account
+            ctx.accounts.mint_account.key(),                // Mint account
+            ctx.accounts.mint_authority.key(),              // Mint authority
+            ctx.accounts.payer.key(),                       // Payer
+            ctx.accounts.mint_authority.key(),              // Update authority
+            token_title,                                    // Name
+            token_symbol,                                   // Symbol
+            token_uri,                                      // URI
+            None,                                           // Creators
+            0,                                              // Seller fee basis points
+            true,                                           // Update authority is signer
+            false,                                          // Is mutable
+            None,                                           // Collection
+            None,                                           // Uses
+            None,                                           // Collection Details
+        ),
+        &[
+            ctx.accounts.metadata_account.to_account_info(),
+            ctx.accounts.mint_account.to_account_info(),
+            ctx.accounts.mint_authority.to_account_info(),
+            ctx.accounts.payer.to_account_info(),
+            ctx.accounts.mint_authority.to_account_info(),
+            ctx.accounts.rent.to_account_info(),
+        ],
+    )?;
+
+    msg!("Token mint created successfully.");
+
+    Ok(())
+}
+
+
+#[derive(Accounts)]
+pub struct CreateToken<'info> {
+    /// CHECK: We're about to create this with Metaplex
+    #[account(mut)]
+    pub metadata_account: UncheckedAccount<'info>,
+    #[account(
+        init,
+        payer = payer,
+        mint::decimals = 9,
+        mint::authority = mint_authority.key(),
+    )]
+    pub mint_account: Account<'info, token::Mint>,
+    pub mint_authority: SystemAccount<'info>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub rent: Sysvar<'info, Rent>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, token::Token>,
+    /// CHECK: Metaplex will check this
+    pub token_metadata_program: UncheckedAccount<'info>,
+}

+ 58 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mint.rs

@@ -0,0 +1,58 @@
+use {
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        token,
+        associated_token,
+    },
+};
+
+
+pub fn mint_to(
+    ctx: Context<MintTo>, 
+    amount: u64,
+) -> Result<()> {
+
+    msg!("Minting token to token account...");
+    msg!("Mint: {}", &ctx.accounts.mint_account.to_account_info().key());   
+    msg!("Token Address: {}", &ctx.accounts.associated_token_account.key());     
+    token::mint_to(
+        CpiContext::new(
+            ctx.accounts.token_program.to_account_info(),
+            token::MintTo {
+                mint: ctx.accounts.mint_account.to_account_info(),
+                to: ctx.accounts.associated_token_account.to_account_info(),
+                authority: ctx.accounts.mint_authority.to_account_info(),
+            },
+        ),
+        amount,
+    )?;
+
+    msg!("Token minted to wallet successfully.");
+
+    Ok(())
+}
+
+
+#[derive(Accounts)]
+pub struct MintTo<'info> {
+    #[account(
+        mut,
+        mint::decimals = 9,
+        mint::authority = mint_authority.key(),
+    )]
+    pub mint_account: Account<'info, token::Mint>,
+    pub mint_authority: SystemAccount<'info>,
+    #[account(
+        init,
+        payer = payer,
+        associated_token::mint = mint_account,
+        associated_token::authority = payer,
+    )]
+    pub associated_token_account: Account<'info, token::TokenAccount>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub rent: Sysvar<'info, Rent>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, token::Token>,
+    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
+}

+ 5 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mod.rs

@@ -0,0 +1,5 @@
+pub mod create;
+pub mod mint;
+
+pub use create::*;
+pub use mint::*;

+ 40 - 0
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/lib.rs

@@ -0,0 +1,40 @@
+use anchor_lang::prelude::*;
+
+pub mod instructions;
+
+use instructions::*;
+
+
+declare_id!("5BStrknWEiQWHmDGdDBaG7j9qegfN2Nq83M3hXajjgXY");
+
+
+#[program]
+pub mod spl_token_minter {
+    use super::*;
+
+    pub fn create_token(
+        ctx: Context<CreateToken>, 
+        token_title: String, 
+        token_symbol: String, 
+        token_uri: String,
+    ) -> Result<()> {
+
+        create::create_token(
+            ctx, 
+            token_title, 
+            token_symbol, 
+            token_uri,
+        )
+    }
+
+    pub fn mint_to(
+        ctx: Context<MintTo>, 
+        quantity: u64,
+    ) -> Result<()> {
+
+        mint::mint_to(
+            ctx, 
+            quantity,
+        )
+    }
+}

+ 81 - 0
tokens/spl-token-minter/anchor/tests/test.ts

@@ -0,0 +1,81 @@
+import { 
+  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
+} from '@metaplex-foundation/mpl-token-metadata';
+import * as anchor from "@project-serum/anchor";
+import { ASSOCIATED_PROGRAM_ID } from '@project-serum/anchor/dist/cjs/utils/token';
+import { SplTokenMinter } from "../target/types/spl_token_minter";
+
+
+describe("SPL Token Minter", () => {
+  
+  const provider = anchor.AnchorProvider.env();
+  anchor.setProvider(provider);
+  const payer = provider.wallet as anchor.Wallet;
+  const program = anchor.workspace.SplTokenMinter as anchor.Program<SplTokenMinter>;
+
+  const tokenTitle = "Solana Gold";
+  const tokenSymbol = "GOLDSOL";
+  const tokenUri = "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json";
+
+  const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
+  
+  it("Create an SPL Token!", async () => {
+
+    const metadataAddress = (await anchor.web3.PublicKey.findProgramAddress(
+      [
+        Buffer.from("metadata"),
+        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+        mintKeypair.publicKey.toBuffer(),
+      ],
+      TOKEN_METADATA_PROGRAM_ID
+    ))[0];
+
+    const sx = await program.methods.createToken(
+      tokenTitle, tokenSymbol, tokenUri
+    )
+      .accounts({
+        metadataAccount: metadataAddress,
+        mintAccount: mintKeypair.publicKey,
+        mintAuthority: payer.publicKey,
+        payer: payer.publicKey,
+        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        systemProgram: anchor.web3.SystemProgram.programId,
+        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+      })
+      .signers([mintKeypair, payer.payer])
+      .rpc();
+
+    console.log("Success!");
+        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+        console.log(`   Tx Signature: ${sx}`);
+  });
+
+  it("Mint some tokens to your wallet!", async () => {
+
+    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
+      mint: mintKeypair.publicKey,
+      owner: payer.publicKey,
+    });
+
+    const sx = await program.methods.mintTo(
+      new anchor.BN(150)
+    )
+      .accounts({
+        associatedTokenAccount: associatedTokenAccountAddress,
+        mintAccount: mintKeypair.publicKey,
+        mintAuthority: payer.publicKey,
+        payer: payer.publicKey,
+        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        systemProgram: anchor.web3.SystemProgram.programId,
+        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+      })
+      .signers([payer.payer])
+      .rpc();
+
+    console.log("Success!");
+        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+        console.log(`   Tx Signature: ${sx}`);
+  });
+});

+ 10 - 0
tokens/spl-token-minter/anchor/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}

+ 8 - 0
tokens/spl-token-minter/native/cicd.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# This script is for quick building & deploying of the program.
+# It also serves as a reference for the commands used for building & deploying Solana programs.
+# Run this bad boy with "bash cicd.sh" or "./cicd.sh"
+
+cargo build-bpf --manifest-path=./program/Cargo.toml
+solana program deploy ./program/target/deploy/program.so

+ 22 - 0
tokens/spl-token-minter/native/package.json

@@ -0,0 +1,22 @@
+{
+  "scripts": {
+    "test": "yarn run ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts"
+  },
+  "dependencies": {
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+    "@solana/spl-token": "^0.2.0",
+    "@solana/web3.js": "^1.47.3",
+    "borsh": "^0.7.0",
+    "buffer": "^6.0.3",
+    "fs": "^0.0.1-security"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.1",
+    "@types/mocha": "^9.1.1",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
+}

+ 15 - 0
tokens/spl-token-minter/native/program/Cargo.toml

@@ -0,0 +1,15 @@
+[package]
+name = "program"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+borsh = "0.9.3"
+borsh-derive = "0.9.1"
+solana-program = "1.10.26"
+spl-token = { version="3.3.0", features = [ "no-entrypoint" ] }
+spl-associated-token-account = { version="1.0.5", features = [ "no-entrypoint" ] }
+mpl-token-metadata = { version="1.2.5", features = [ "no-entrypoint" ] }
+
+[lib]
+crate-type = ["cdylib", "lib"]

+ 125 - 0
tokens/spl-token-minter/native/program/src/instructions/create.rs

@@ -0,0 +1,125 @@
+use {
+    borsh::{ 
+        BorshDeserialize, 
+        BorshSerialize, 
+    },
+    solana_program::{
+        account_info::{next_account_info, AccountInfo}, 
+        entrypoint::ProgramResult, 
+        msg, 
+        program::invoke,
+        program_pack::Pack,
+        rent::Rent,
+        system_instruction,
+        sysvar::Sysvar,
+    },
+    spl_token::{
+        instruction as token_instruction,
+        state::Mint,
+    },
+    mpl_token_metadata::{
+        instruction as mpl_instruction,
+    },
+};
+
+
+#[derive(BorshSerialize, BorshDeserialize, Debug)]
+pub struct CreateTokenArgs {
+    pub token_title: String,
+    pub token_symbol: String,
+    pub token_uri: String,
+}
+
+
+pub fn create_token(
+    accounts: &[AccountInfo],
+    args: CreateTokenArgs,
+) -> ProgramResult {
+
+    let accounts_iter = &mut accounts.iter();
+
+    let mint_account = next_account_info(accounts_iter)?;
+    let mint_authority = next_account_info(accounts_iter)?;
+    let metadata_account = next_account_info(accounts_iter)?;
+    let payer = next_account_info(accounts_iter)?;
+    let rent = next_account_info(accounts_iter)?;
+    let system_program = next_account_info(accounts_iter)?;
+    let token_program = next_account_info(accounts_iter)?;
+    let token_metadata_program = next_account_info(accounts_iter)?;
+
+    // First create the account for the Mint
+    //
+    msg!("Creating mint account...");
+    msg!("Mint: {}", mint_account.key);
+    invoke(
+        &system_instruction::create_account(
+            &payer.key,
+            &mint_account.key,
+            (Rent::get()?).minimum_balance(Mint::LEN),
+            Mint::LEN as u64,
+            &token_program.key,
+        ),
+        &[
+            mint_account.clone(),
+            payer.clone(),
+            system_program.clone(),
+            token_program.clone(),
+        ]
+    )?;
+
+    // Now initialize that account as a Mint (standard Mint)
+    //
+    msg!("Initializing mint account...");
+    msg!("Mint: {}", mint_account.key);
+    invoke(
+        &token_instruction::initialize_mint(
+            &token_program.key,
+            &mint_account.key,
+            &mint_authority.key,
+            Some(&mint_authority.key),
+            9,                          // 9 Decimals for the default SPL Token standard
+        )?,
+        &[
+            mint_account.clone(),
+            mint_authority.clone(),
+            token_program.clone(),
+            rent.clone(),
+        ]
+    )?;
+
+    // Now create the account for that Mint's metadata
+    //
+    msg!("Creating metadata account...");
+    msg!("Metadata account address: {}", metadata_account.key);
+    invoke(
+        &mpl_instruction::create_metadata_accounts_v2(
+            *token_metadata_program.key,
+            *metadata_account.key,
+            *mint_account.key,
+            *mint_authority.key,
+            *payer.key,
+            *mint_authority.key,
+            args.token_title,
+            args.token_symbol,
+            args.token_uri,
+            None,
+            0,
+            true,
+            false,
+            None,
+            None,
+        ),
+        &[
+            metadata_account.clone(),
+            mint_account.clone(),
+            mint_authority.clone(),
+            payer.clone(),
+            token_metadata_program.clone(),
+            rent.clone(),
+        ]
+    )?;
+
+    msg!("Token mint created successfully.");
+
+    Ok(())
+}

+ 86 - 0
tokens/spl-token-minter/native/program/src/instructions/mint.rs

@@ -0,0 +1,86 @@
+use {
+    borsh::{ 
+        BorshDeserialize, 
+        BorshSerialize, 
+    },
+    solana_program::{
+        account_info::{next_account_info, AccountInfo},
+        entrypoint::ProgramResult, 
+        msg, 
+        program::invoke,
+    },
+    spl_token::{
+        instruction as token_instruction,
+    },
+    spl_associated_token_account::{
+        instruction as associated_token_account_instruction,
+    },
+};
+
+
+#[derive(BorshSerialize, BorshDeserialize, Debug)]
+pub struct MintToArgs {
+    pub quantity: u64,
+}
+
+
+pub fn mint_to(
+    accounts: &[AccountInfo],
+    args: MintToArgs,
+) -> ProgramResult {
+
+    let accounts_iter = &mut accounts.iter();
+
+    let mint_account = next_account_info(accounts_iter)?;
+    let mint_authority = next_account_info(accounts_iter)?;
+    let associated_token_account = next_account_info(accounts_iter)?;
+    let payer = next_account_info(accounts_iter)?;
+    let _rent = next_account_info(accounts_iter)?;
+    let _system_program = next_account_info(accounts_iter)?;
+    let token_program = next_account_info(accounts_iter)?;
+    let associated_token_program = next_account_info(accounts_iter)?;
+
+    if associated_token_account.lamports() == 0 {
+        msg!("Creating associated token account...");
+        invoke(
+            &associated_token_account_instruction::create_associated_token_account(
+                &payer.key,
+                &payer.key,
+                &mint_account.key,
+            ),
+            &[
+                mint_account.clone(),
+                associated_token_account.clone(),
+                payer.clone(),
+                token_program.clone(),
+                associated_token_program.clone(),
+            ]
+        )?;
+    } else {
+        msg!("Associated token account exists.");
+    }
+    msg!("Associated Token Address: {}", associated_token_account.key);
+
+    msg!("Minting {} tokens to associated token account...", args.quantity);
+    invoke(
+        &token_instruction::mint_to(
+            &token_program.key,
+            &mint_account.key,
+            &associated_token_account.key,
+            &mint_authority.key,
+            &[&mint_authority.key],
+            args.quantity,
+        )?,
+        &[
+            mint_account.clone(),
+            mint_authority.clone(),
+            associated_token_account.clone(),
+            token_program.clone(),
+        ],
+    )?;
+
+    msg!("Tokens minted to wallet successfully.");
+
+    Ok(())
+}
+

+ 5 - 0
tokens/spl-token-minter/native/program/src/instructions/mod.rs

@@ -0,0 +1,5 @@
+pub mod create;
+pub mod mint;
+
+pub use create::*;
+pub use mint::*;

+ 22 - 0
tokens/spl-token-minter/native/program/src/lib.rs

@@ -0,0 +1,22 @@
+use solana_program::{
+    account_info::AccountInfo, 
+    entrypoint, 
+    entrypoint::ProgramResult, 
+    pubkey::Pubkey,
+};
+
+pub mod processor;
+pub mod instructions;
+
+
+entrypoint!(process_instruction);
+
+
+fn process_instruction(
+    program_id: &Pubkey,
+    accounts: &[AccountInfo],
+    instruction_data: &[u8],
+) -> ProgramResult {
+
+    processor::process_instruction(program_id, accounts, instruction_data)
+}

+ 44 - 0
tokens/spl-token-minter/native/program/src/processor.rs

@@ -0,0 +1,44 @@
+use {
+    borsh::{ 
+        BorshDeserialize, 
+        BorshSerialize, 
+    },
+    solana_program::{
+        account_info::AccountInfo, 
+        entrypoint::ProgramResult, 
+        pubkey::Pubkey,
+    },
+};
+
+use crate::instructions::{ 
+    create::{
+        CreateTokenArgs,
+        create_token,
+    }, 
+    mint::{
+        MintToArgs,
+        mint_to,
+    }, 
+};
+
+
+#[derive(BorshSerialize, BorshDeserialize, Debug)]
+enum SplMinterIntstruction {
+    Create(CreateTokenArgs),
+    Mint(MintToArgs),
+}
+
+
+pub fn process_instruction(
+    _program_id: &Pubkey,
+    accounts: &[AccountInfo],
+    instruction_data: &[u8],
+) -> ProgramResult {
+
+    let instruction = SplMinterIntstruction::try_from_slice(instruction_data)?;
+
+    match instruction {
+        SplMinterIntstruction::Create(args) => create_token(accounts, args),
+        SplMinterIntstruction::Mint(args) => mint_to(accounts, args),
+    }
+}

+ 51 - 0
tokens/spl-token-minter/native/tests/instructions.ts

@@ -0,0 +1,51 @@
+import * as borsh from "borsh";
+
+
+class Assignable {
+    constructor(properties) {
+        Object.keys(properties).map((key) => {
+            return (this[key] = properties[key]);
+        });
+    };
+};
+
+export enum SplMinterInstruction {
+    Create,
+    Mint,
+}
+
+export class CreateTokenArgs extends Assignable {
+    toBuffer() {
+        return Buffer.from(borsh.serialize(CreateTokenArgsSchema, this));
+    }
+};
+const CreateTokenArgsSchema = new Map([
+    [
+        CreateTokenArgs, {
+            kind: 'struct',
+            fields: [
+                ['instruction', 'u8'],
+                ['token_title', 'string'],
+                ['token_symbol', 'string'],
+                ['token_uri', 'string'],
+            ]
+        }
+    ]
+]);
+
+export class MintToArgs extends Assignable {
+    toBuffer() {
+        return Buffer.from(borsh.serialize(MintToArgsSchema, this));
+    }
+};
+const MintToArgsSchema = new Map([
+    [
+        MintToArgs, {
+            kind: 'struct',
+            fields: [
+                ['instruction', 'u8'],
+                ['quantity', 'u64'],
+            ]
+        }
+    ]
+]);

+ 125 - 0
tokens/spl-token-minter/native/tests/test.ts

@@ -0,0 +1,125 @@
+import { 
+    PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
+} from '@metaplex-foundation/mpl-token-metadata';
+import {
+    Connection,
+    Keypair,
+    PublicKey,
+    SystemProgram,
+    SYSVAR_RENT_PUBKEY,
+    TransactionInstruction,
+    Transaction,
+    sendAndConfirmTransaction,
+} from '@solana/web3.js';
+import {
+    ASSOCIATED_TOKEN_PROGRAM_ID,
+    getAssociatedTokenAddress,
+    TOKEN_PROGRAM_ID,
+} from '@solana/spl-token';
+import { Buffer } from "buffer";
+import { 
+    CreateTokenArgs,
+    MintToArgs,
+    SplMinterInstruction,
+} from './instructions';
+import { BN } from 'bn.js';
+
+
+function createKeypairFromFile(path: string): Keypair {
+    return Keypair.fromSecretKey(
+        Buffer.from(JSON.parse(require('fs').readFileSync(path, "utf-8")))
+    )
+};
+
+
+describe("SPL Token Minter", async () => {
+
+    // const connection = new Connection(`http://localhost:8899`, 'confirmed');
+    const connection = new Connection(`https://api.devnet.solana.com/`, 'confirmed');
+    const payer = createKeypairFromFile(require('os').homedir() + '/.config/solana/id.json');
+    const program = createKeypairFromFile('./program/target/deploy/program-keypair.json');
+
+    const mintKeypair: Keypair = Keypair.generate();
+
+    it("Create an SPL Token!", async () => {
+
+        const metadataAddress = (PublicKey.findProgramAddressSync(
+            [
+              Buffer.from("metadata"),
+              TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+              mintKeypair.publicKey.toBuffer(),
+            ],
+            TOKEN_METADATA_PROGRAM_ID
+        ))[0];
+        
+        const instructionData = new CreateTokenArgs({
+            instruction: SplMinterInstruction.Create,
+            token_title: "Solana Gold",
+            token_symbol: "GOLDSOL",
+            token_uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
+        });
+
+        let ix = new TransactionInstruction({
+            keys: [
+                { pubkey: mintKeypair.publicKey, isSigner: true, isWritable: true },            // Mint account
+                { pubkey: payer.publicKey, isSigner: false, isWritable: true },                 // Mint authority account
+                { pubkey: metadataAddress, isSigner: false, isWritable: true },                 // Metadata account
+                { pubkey: payer.publicKey, isSigner: true, isWritable: true },                  // Payer
+                { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },             // Rent account
+                { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },        // System program
+                { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },               // Token program
+                { pubkey: TOKEN_METADATA_PROGRAM_ID, isSigner: false, isWritable: false },      // Token metadata program
+            ],
+            programId: program.publicKey,
+            data: instructionData.toBuffer(),
+        });
+
+        const sx = await sendAndConfirmTransaction(
+            connection, 
+            new Transaction().add(ix),
+            [payer, mintKeypair]
+        );
+
+        console.log("Success!");
+        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+        console.log(`   Tx Signature: ${sx}`);
+    });
+
+    it("Mint some tokens to your wallet!", async () => {
+
+        const associatedTokenAccountAddress = await getAssociatedTokenAddress(
+            mintKeypair.publicKey,
+            payer.publicKey,
+        );
+        
+        const instructionData = new MintToArgs({
+            instruction: SplMinterInstruction.Mint,
+            quantity: new BN(150),
+        });
+
+        let ix = new TransactionInstruction({
+            keys: [
+                { pubkey: mintKeypair.publicKey, isSigner: false, isWritable: true },           // Mint account
+                { pubkey: payer.publicKey, isSigner: false, isWritable: true },                 // Mint authority account
+                { pubkey: associatedTokenAccountAddress, isSigner: false, isWritable: true },   // ATA
+                { pubkey: payer.publicKey, isSigner: true, isWritable: true },                  // Payer
+                { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },             // Rent account
+                { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },        // System program
+                { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },               // Token program
+                { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },    // Token metadata program
+            ],
+            programId: program.publicKey,
+            data: instructionData.toBuffer(),
+        });
+
+        const sx = await sendAndConfirmTransaction(
+            connection, 
+            new Transaction().add(ix),
+            [payer]
+        );
+
+        console.log("Success!");
+        console.log(`   ATA Address: ${associatedTokenAccountAddress}`);
+        console.log(`   Tx Signature: ${sx}`);
+  });
+});

+ 10 - 0
tokens/spl-token-minter/native/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true,
+  }
+}