Skip to content

Commit a68f590

Browse files
docs(examples): add createMint runnable example
Adds rpc/examples/createMint demonstrating the idiomatic way to create a new SPL Token mint — the two-instruction composition readers have historically had to reconstruct themselves: 1. system.CreateAccount allocates 82 bytes funded to the rent-exempt minimum, owned by token.ProgramID. 2. token.InitializeMint2 writes the mint state (decimals, mint authority, freeze authority). Mint2 is preferred over Mint because Token v1.1+ dropped the Rent sysvar the original required. The example runs end-to-end on devnet: generate payer + mint keypair, airdrop, fetch rent via GetMinimumBalanceForRentExemption, build both instructions, sign with both keypairs (the mint keypair authorizes creation at its own pubkey), and SendTransaction. Inline comments point to the Token-2022 variant and note where extensions would slot in before InitializeMint2. Closes #277
1 parent 828ac78 commit a68f590

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2026 github.com/gagliardetto
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+
15+
// createMint builds and submits the two-instruction transaction that
16+
// creates a new SPL Token mint on devnet:
17+
//
18+
// 1. system.CreateAccount — allocates a 82-byte account funded with
19+
// the rent-exempt minimum, owned by the Token program.
20+
// 2. token.InitializeMint2 — writes the mint state (decimals, mint
21+
// authority, freeze authority). Prefer Mint2 over Mint: v1.1+ of
22+
// the Token program dropped the Rent sysvar account that the
23+
// original instruction required.
24+
//
25+
// Swap token.ProgramID for token2022.ProgramID (and import the sibling
26+
// package) to create a Token-2022 mint. Extensions must be initialized
27+
// between CreateAccount and InitializeMint2, and the account allocated
28+
// larger than MINT_SIZE accordingly.
29+
package main
30+
31+
import (
32+
"context"
33+
"fmt"
34+
"time"
35+
36+
"github.com/gagliardetto/solana-go"
37+
"github.com/gagliardetto/solana-go/programs/system"
38+
"github.com/gagliardetto/solana-go/programs/token"
39+
"github.com/gagliardetto/solana-go/rpc"
40+
)
41+
42+
func main() {
43+
ctx := context.Background()
44+
client := rpc.New(rpc.DevNet_RPC)
45+
46+
// In real code, load an existing keypair instead of generating one:
47+
// payer, _ := solana.PrivateKeyFromSolanaKeygenFile("/path/to/id.json")
48+
payer := solana.NewWallet()
49+
mint := solana.NewWallet()
50+
fmt.Println("payer:", payer.PublicKey())
51+
fmt.Println("mint: ", mint.PublicKey())
52+
53+
airdropSig, err := client.RequestAirdrop(
54+
ctx,
55+
payer.PublicKey(),
56+
solana.LAMPORTS_PER_SOL,
57+
rpc.CommitmentFinalized,
58+
)
59+
if err != nil {
60+
panic(fmt.Errorf("airdrop: %w", err))
61+
}
62+
fmt.Println("airdrop signature:", airdropSig)
63+
time.Sleep(20 * time.Second) // wait for the airdrop to finalize
64+
65+
// Rent-exempt minimum lamports for a 82-byte (MINT_SIZE) account.
66+
rentLamports, err := client.GetMinimumBalanceForRentExemption(
67+
ctx,
68+
token.MINT_SIZE,
69+
rpc.CommitmentFinalized,
70+
)
71+
if err != nil {
72+
panic(fmt.Errorf("get min balance for rent exemption: %w", err))
73+
}
74+
75+
recent, err := client.GetLatestBlockhash(ctx, rpc.CommitmentFinalized)
76+
if err != nil {
77+
panic(fmt.Errorf("get blockhash: %w", err))
78+
}
79+
80+
createAccountIx := system.NewCreateAccountInstruction(
81+
rentLamports,
82+
token.MINT_SIZE,
83+
token.ProgramID, // owner: the Token program
84+
payer.PublicKey(), // funding account
85+
mint.PublicKey(), // the new account (the mint itself)
86+
).Build()
87+
88+
initMintIx := token.NewInitializeMint2Instruction(
89+
9, // decimals
90+
payer.PublicKey(), // mint authority
91+
solana.PublicKey{}, // freeze authority; pass a zero pubkey to disable
92+
mint.PublicKey(),
93+
).Build()
94+
95+
tx, err := solana.NewTransaction(
96+
[]solana.Instruction{createAccountIx, initMintIx},
97+
recent.Value.Blockhash,
98+
solana.TransactionPayer(payer.PublicKey()),
99+
)
100+
if err != nil {
101+
panic(fmt.Errorf("build tx: %w", err))
102+
}
103+
104+
// Both keypairs must sign: the mint keypair authorizes creation at
105+
// its own pubkey, and the payer funds it.
106+
if _, err := tx.Sign(func(key solana.PublicKey) *solana.PrivateKey {
107+
switch {
108+
case payer.PublicKey().Equals(key):
109+
return &payer.PrivateKey
110+
case mint.PublicKey().Equals(key):
111+
return &mint.PrivateKey
112+
}
113+
return nil
114+
}); err != nil {
115+
panic(fmt.Errorf("sign: %w", err))
116+
}
117+
118+
sig, err := client.SendTransaction(ctx, tx)
119+
if err != nil {
120+
panic(fmt.Errorf("send: %w", err))
121+
}
122+
123+
fmt.Println("created mint:", mint.PublicKey())
124+
fmt.Println("tx signature:", sig)
125+
}

0 commit comments

Comments
 (0)