Browse Source

mint token

jpcaulfi 3 years ago
parent
commit
97519718e5

+ 14 - 0
nfts/mint/anchor/Anchor.toml

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

+ 13 - 0
nfts/mint/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

+ 14 - 0
nfts/mint/anchor/package.json

@@ -0,0 +1,14 @@
+{
+    "dependencies": {
+        "@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"
+    }
+}

+ 19 - 0
nfts/mint/anchor/programs/hello-solana/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "hello-solana"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "hello_solana"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = "0.24.2"

+ 2 - 0
nfts/mint/anchor/programs/hello-solana/Xargo.toml

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

+ 18 - 0
nfts/mint/anchor/programs/hello-solana/src/lib.rs

@@ -0,0 +1,18 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod hello_solana {
+    use super::*;
+
+    pub fn hello(ctx: Context<Hello>) -> Result<()> {
+        
+        msg!("Hello, Solana!");
+        
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Hello {}

+ 22 - 0
nfts/mint/anchor/tests/test.ts

@@ -0,0 +1,22 @@
+import * as anchor from "@project-serum/anchor";
+import { HelloSolana } from "../target/types/hello_solana";
+
+describe("hello-solana", () => {
+  
+  // Configure the Anchor provider & load the program IDL
+  // The IDL gives you a typescript module
+  //
+  const provider = anchor.AnchorProvider.env();
+  anchor.setProvider(provider);
+  const program = anchor.workspace.HelloSolana as anchor.Program<HelloSolana>;
+
+  it("Say hello!", async () => {
+    
+    // Just run Anchor's IDL method to build a transaction!
+    //
+    await program.methods.hello()
+    .accounts({})
+    .rpc();
+
+  });
+});

+ 10 - 0
nfts/mint/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
nfts/mint/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 --bpf-out-dir=./program/target/so
+solana program deploy ./program/target/so/program.so

+ 18 - 0
nfts/mint/native/package.json

@@ -0,0 +1,18 @@
+{
+  "scripts": {
+    "test": "yarn run ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts"
+  },
+  "dependencies": {
+    "@solana/web3.js": "^1.47.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"
+  }
+}

+ 10 - 0
nfts/mint/native/program/Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "program"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+solana-program = "1.10.12"
+
+[lib]
+crate-type = ["cdylib", "lib"]

+ 29 - 0
nfts/mint/native/program/src/lib.rs

@@ -0,0 +1,29 @@
+use solana_program::{
+    account_info::AccountInfo, 
+    entrypoint, 
+    entrypoint::ProgramResult, 
+    msg, 
+    pubkey::Pubkey,
+};
+
+
+// Tells Solana that the entrypoint to this program
+//  is the "process_instruction" function.
+//
+entrypoint!(process_instruction);
+
+
+// Our entrypoint's parameters have to match the
+//  anatomy of a transaction instruction (see README).
+//
+fn process_instruction(
+    program_id: &Pubkey,
+    accounts: &[AccountInfo],
+    instruction_data: &[u8],
+) -> ProgramResult {
+
+    
+    msg!("Hello, Solana!");
+
+    Ok(())
+}

+ 45 - 0
nfts/mint/native/tests/test.ts

@@ -0,0 +1,45 @@
+import {
+    Connection,
+    Keypair,
+    sendAndConfirmTransaction,
+    Transaction,
+    TransactionInstruction,
+} from '@solana/web3.js';
+
+function createKeypairFromFile(path: string): Keypair {
+    return Keypair.fromSecretKey(
+        Buffer.from(JSON.parse(require('fs').readFileSync(path, "utf-8")))
+    )
+};
+
+
+describe("hello-solana", () => {
+
+    // Loading these from local files for development
+    //
+    const connection = new Connection(`http://localhost:8899`, 'confirmed');
+    const payer = createKeypairFromFile(require('os').homedir() + '/.config/solana/id.json');
+    const program = createKeypairFromFile('./program/target/so/program-keypair.json');
+  
+    it("Say hello!", async () => {
+
+        // We set up our instruction first.
+        //
+        let ix = new TransactionInstruction({
+            keys: [
+                {pubkey: payer.publicKey, isSigner: true, isWritable: true}
+            ],
+            programId: program.publicKey,
+            data: Buffer.alloc(0), // No data
+        });
+
+        // Now we send the transaction over RPC
+        //
+        await sendAndConfirmTransaction(
+            connection, 
+            new Transaction().add(ix), // Add our instruction (you can add more than one)
+            [payer]
+        );
+    });
+  });
+  

+ 10 - 0
nfts/mint/native/tsconfig.json

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

+ 3 - 0
tokens/README.md

@@ -0,0 +1,3 @@
+## :warning: All token examples are on devnet!
+
+`https://api.devnet.solana.com/`

+ 16 - 0
tokens/mint/README.md

@@ -0,0 +1,16 @@
+# Create a New SPL Token Mint
+
+This example demonstrates how to create an SPl Token on Solana with some metadata such as a token symbol and icon.
+
+### About Tokens
+
+Tokens on Solana are - like everything else on Solana - accounts! They:
+- are owned by the Token Program
+- can only be changed by the Token Program
+- have an associated Mint Authority - the only account that can mint new tokens (by calling the Token program)
+
+How they work:   
+:apple: `Mint Account` - stores information about the token.
+:handbag: `Associated Token Account` - stores a specific balance of the Mint Account (this is essentially a counter).
+
+> You can read all about tokens in [Solana's official SPL Token documentation](https://spl.solana.com/token).

+ 14 - 0
tokens/mint/anchor/Anchor.toml

@@ -0,0 +1,14 @@
+[features]
+seeds = false
+[programs.devnet]
+mint_token = "3hmFGLkjJc7TfSLdEYYYwGAz6KsrD8anYwtSkF6TYjBU"
+
+[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/mint/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

+ 14 - 0
tokens/mint/anchor/package.json

@@ -0,0 +1,14 @@
+{
+    "dependencies": {
+        "@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/mint/anchor/programs/mint-token/Cargo.toml

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

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

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

+ 109 - 0
tokens/mint/anchor/programs/mint-token/src/lib.rs

@@ -0,0 +1,109 @@
+use {
+    anchor_lang::{
+        prelude::*,
+        solana_program::program::invoke,
+        system_program,
+    },
+    anchor_spl::token,
+    mpl_token_metadata::{
+        ID as TOKEN_METADATA_ID,
+        instruction as mpl_instruction,
+    },
+};
+
+
+declare_id!("3hmFGLkjJc7TfSLdEYYYwGAz6KsrD8anYwtSkF6TYjBU");
+
+
+#[program]
+pub mod mint_token {
+    use super::*;
+
+    pub fn mint_token(
+        ctx: Context<MintToken>, 
+        metadata_title: String, 
+        metadata_symbol: String, 
+        metadata_uri: String,
+    ) -> Result<()> {
+
+        msg!("Creating mint account...");
+        msg!("Mint: {}", &ctx.accounts.mint_account.key());
+        system_program::create_account(
+            CpiContext::new(
+                ctx.accounts.token_program.to_account_info(),
+                system_program::CreateAccount {
+                    from: ctx.accounts.mint_authority.to_account_info(),
+                    to: ctx.accounts.mint_account.to_account_info(),
+                },
+            ),
+            10000000,
+            82,
+            &ctx.accounts.token_program.key(),
+        )?;
+
+        msg!("Initializing mint account...");
+        msg!("Mint: {}", &ctx.accounts.mint_account.key());
+        token::initialize_mint(
+            CpiContext::new(
+                ctx.accounts.token_program.to_account_info(),
+                token::InitializeMint {
+                    mint: ctx.accounts.mint_account.to_account_info(),
+                    rent: ctx.accounts.rent.to_account_info(),
+                },
+            ),
+            9,
+            &ctx.accounts.mint_authority.key(),
+            Some(&ctx.accounts.mint_authority.key()),
+        )?;
+
+        msg!("Creating metadata account...");
+        msg!("Metadata account address: {}", &ctx.accounts.metadata_account.key());
+        invoke(
+            &mpl_instruction::create_metadata_accounts_v2(
+                TOKEN_METADATA_ID, 
+                ctx.accounts.metadata_account.key(), 
+                ctx.accounts.mint_account.key(), 
+                ctx.accounts.mint_authority.key(), 
+                ctx.accounts.mint_authority.key(), 
+                ctx.accounts.mint_authority.key(), 
+                metadata_title, 
+                metadata_symbol, 
+                metadata_uri, 
+                None,
+                1,
+                true, 
+                false, 
+                None, 
+                None,
+            ),
+            &[
+                ctx.accounts.metadata_account.to_account_info(),
+                ctx.accounts.mint_account.to_account_info(),
+                ctx.accounts.mint_authority.to_account_info(),
+                ctx.accounts.token_metadata_program.to_account_info(),
+                ctx.accounts.rent.to_account_info(),
+            ],
+        )?;
+
+        msg!("Token mint process completed successfully.");
+
+        Ok(())
+    }
+}
+
+
+#[derive(Accounts)]
+pub struct MintToken<'info> {
+    /// CHECK: We're about to create this with Metaplex
+    #[account(mut)]
+    pub metadata_account: UncheckedAccount<'info>,
+    #[account(mut)]
+    pub mint_account: Signer<'info>,
+    #[account(mut)]
+    pub mint_authority: 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>,
+}

+ 52 - 0
tokens/mint/anchor/tests/test.ts

@@ -0,0 +1,52 @@
+import * as anchor from "@project-serum/anchor";
+import { MintToken } from "../target/types/mint_token";
+
+
+const TOKEN_METADATA_PROGRAM_ID = new anchor.web3.PublicKey(
+  "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
+);
+
+
+describe("mint-token", () => {
+  
+  const provider = anchor.AnchorProvider.env();
+  anchor.setProvider(provider);
+  const payer = provider.wallet as anchor.Wallet;
+  const program = anchor.workspace.MintToken as anchor.Program<MintToken>;
+
+  it("Mint!", async () => {
+
+    const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
+    console.log(`New token: ${mintKeypair.publicKey}`);
+
+    // Derive the metadata account's address and set the metadata
+    //
+    const metadataAddress = (await anchor.web3.PublicKey.findProgramAddress(
+      [
+        Buffer.from("metadata"),
+        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+        mintKeypair.publicKey.toBuffer(),
+      ],
+      TOKEN_METADATA_PROGRAM_ID
+    ))[0];
+    const testNftTitle = "Solana Gold";
+    const testNftSymbol = "GOLDSOL";
+    const testNftUri = "https://raw.githubusercontent.com/solana-developers/program-examples/main/tokens/mint/native/assets/token_metadata.json";
+
+    // Transact with the "mint_token" function in our on-chain program
+    //
+    await program.methods.mintToken(
+      testNftTitle, testNftSymbol, testNftUri
+    )
+    .accounts({
+      metadataAccount: metadataAddress,
+      mintAccount: mintKeypair.publicKey,
+      mintAuthority: payer.publicKey,
+      systemProgram: anchor.web3.SystemProgram.programId,
+      tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+      tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+    })
+    .signers([payer.payer, mintKeypair])
+    .rpc();
+  });
+});

+ 10 - 0
tokens/mint/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/mint/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 --bpf-out-dir=./program/target/so
+solana program deploy ./program/target/so/program.so

+ 21 - 0
tokens/mint/native/package.json

@@ -0,0 +1,21 @@
+{
+  "scripts": {
+    "test": "yarn run ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts"
+  },
+  "dependencies": {
+    "@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"
+  }
+}

+ 14 - 0
tokens/mint/native/program/Cargo.toml

@@ -0,0 +1,14 @@
+[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" ] }
+mpl-token-metadata = { version="1.2.5", features = [ "no-entrypoint" ] }
+
+[lib]
+crate-type = ["cdylib", "lib"]

+ 119 - 0
tokens/mint/native/program/src/lib.rs

@@ -0,0 +1,119 @@
+use {
+    borsh::{
+        BorshSerialize, BorshDeserialize,
+    },
+    solana_program::{
+        account_info::{next_account_info, AccountInfo}, 
+        entrypoint, 
+        entrypoint::ProgramResult, 
+        msg, 
+        native_token::LAMPORTS_PER_SOL,
+        program::invoke,
+        pubkey::Pubkey,
+        system_instruction,
+    },
+    spl_token::{
+        instruction as token_instruction,
+    },
+    mpl_token_metadata::{
+        instruction as mpl_instruction,
+    },
+};
+
+
+entrypoint!(process_instruction);
+
+
+fn process_instruction(
+    _program_id: &Pubkey,
+    accounts: &[AccountInfo],
+    instruction_data: &[u8],
+) -> ProgramResult {
+
+    let accounts_iter = &mut accounts.iter();
+
+    let mint_account = next_account_info(accounts_iter)?;
+    let metadata_account = next_account_info(accounts_iter)?;
+    let mint_authority = 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)?;
+
+    let token_metadata = TokenMetadata::try_from_slice(instruction_data)?;
+    
+    msg!("Creating mint account...");
+    msg!("Mint: {}", mint_account.key);
+    invoke(
+        &system_instruction::create_account(
+            &mint_authority.key,
+            &mint_account.key,
+            LAMPORTS_PER_SOL,
+            82,
+            &token_program.key,
+        ),
+        &[
+            mint_account.clone(),
+            mint_authority.clone(),
+            token_program.clone(),
+        ]
+    )?;
+
+    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,
+        )?,
+        &[
+            mint_account.clone(),
+            mint_authority.clone(),
+            token_program.clone(),
+            rent.clone(),
+        ]
+    )?;
+
+    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, 
+            *mint_authority.key, 
+            *mint_authority.key, 
+            token_metadata.title,
+            token_metadata.symbol,
+            token_metadata.uri,
+            None,
+            1,
+            true, 
+            false, 
+            None, 
+            None,
+        ),
+        &[
+            metadata_account.clone(),
+            mint_account.clone(),
+            mint_authority.clone(),
+            token_metadata_program.clone(),
+            rent.clone(),
+        ],
+    )?;
+
+    msg!("Token mint process completed successfully.");
+
+    Ok(())
+}
+
+#[derive(BorshSerialize, BorshDeserialize, Debug)]
+pub struct TokenMetadata {
+    title: String,
+    symbol: String,
+    uri: String,
+}

+ 139 - 0
tokens/mint/native/tests/test.ts

@@ -0,0 +1,139 @@
+import {
+    Connection,
+    Keypair,
+    PublicKey,
+    SystemProgram,
+    SYSVAR_RENT_PUBKEY,
+    TransactionInstruction,
+    Transaction,
+    sendAndConfirmTransaction,
+} from '@solana/web3.js';
+import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
+import * as borsh from "borsh";
+import { Buffer } from "buffer";
+
+
+const TOKEN_METADATA_PROGRAM_ID = new PublicKey(
+    "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
+);
+
+
+function createKeypairFromFile(path: string): Keypair {
+    return Keypair.fromSecretKey(
+        Buffer.from(JSON.parse(require('fs').readFileSync(path, "utf-8")))
+    )
+};
+
+
+describe("mint-token", () => {
+
+    const connection = new Connection(`http://api.devnet.solana.com/`, 'confirmed');
+    const payer = createKeypairFromFile(require('os').homedir() + '/.config/solana/id.json');
+    const program = createKeypairFromFile('./program/target/so/program-keypair.json');
+
+    class Assignable {
+        constructor(properties) {
+            Object.keys(properties).map((key) => {
+                return (this[key] = properties[key]);
+            });
+        };
+    };
+
+    class TokenMetadata extends Assignable {
+        toBuffer() {
+            return Buffer.from(borsh.serialize(TokenMetadataSchema, this));
+        }
+    };
+
+    const TokenMetadataSchema = new Map([
+        [
+            TokenMetadata, {
+                kind: 'struct',
+                fields: [
+                    ['title', 'string'],
+                    ['symbol', 'string'],
+                    ['uri', 'string'],
+                ]
+            }
+        ]
+    ]);
+  
+    it("Mint!", async () => {
+
+        const mintKeypair: Keypair = Keypair.generate();
+        console.log(`New token: ${mintKeypair.publicKey}`);
+
+        // Derive the metadata account's address and set the metadata
+        //
+        const metadataAddress = (await PublicKey.findProgramAddress(
+            [
+              Buffer.from("metadata"),
+              TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+              mintKeypair.publicKey.toBuffer(),
+            ],
+            TOKEN_METADATA_PROGRAM_ID
+        ))[0];
+        const metadata = new TokenMetadata({
+            title: "Solana Gold",
+            symbol: "GOLDSOL",
+            uri: "https://raw.githubusercontent.com/solana-developers/program-examples/main/tokens/mint/native/assets/token_metadata.json",
+        });
+
+        // Transact with the "mint_token" function in our on-chain program
+        //
+        let ix = new TransactionInstruction({
+            keys: [
+                // Mint account
+                {
+                    pubkey: mintKeypair.publicKey,
+                    isSigner: true,
+                    isWritable: true,
+                },
+                // Metadata account
+                {
+                    pubkey: metadataAddress,
+                    isSigner: false,
+                    isWritable: true,
+                },
+                // Mint Authority
+                {
+                    pubkey: payer.publicKey,
+                    isSigner: true,
+                    isWritable: false,
+                },
+                // Rent account
+                {
+                    pubkey: SYSVAR_RENT_PUBKEY,
+                    isSigner: false,
+                    isWritable: false,
+                },
+                // System program
+                {
+                    pubkey: SystemProgram.programId,
+                    isSigner: false,
+                    isWritable: false,
+                },
+                // Token program
+                {
+                    pubkey: TOKEN_PROGRAM_ID,
+                    isSigner: false,
+                    isWritable: false,
+                },
+                {
+                    pubkey: TOKEN_METADATA_PROGRAM_ID,
+                    isSigner: false,
+                    isWritable: false,
+                },
+            ],
+            programId: program.publicKey,
+            data: metadata.toBuffer(),
+        });
+
+        await sendAndConfirmTransaction(
+            connection, 
+            new Transaction().add(ix),
+            [payer, mintKeypair]
+        );
+    });
+  });
+  

+ 10 - 0
tokens/mint/native/tsconfig.json

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