Skip to content

Commit 82e5f16

Browse files
authored
feat: SPL Token fundraiser program example (#82)
* Initial Commit * Create readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Update readme.MD * Removed mint account from contribution. Added require check to checker * minor changes * added close constraint * Update readme.MD * Major changes performed * Update readme.MD * Reworked according to review * Update fundraiser.ts * Ran biome checks * minor changes * Added pnpm lock file * updated to anchor 0.30.1 * Added nft operations example * fixed .ts files * minor changes * Update readme.MD
1 parent 86b33fa commit 82e5f16

33 files changed

+3951
-0
lines changed
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[toolchain]
2+
3+
[features]
4+
seeds = false
5+
skip-lint = false
6+
7+
[programs.localnet]
8+
mint_nft = "3EMcczaGi9ivdLxvvFwRbGYeEUEHpGwabXegARw4jLxa"
9+
10+
[programs.devnet]
11+
mint_nft = "3EMcczaGi9ivdLxvvFwRbGYeEUEHpGwabXegARw4jLxa"
12+
13+
[registry]
14+
url = "https://api.apr.dev"
15+
16+
[provider]
17+
cluster = "devnet"
18+
wallet = "~/.config/solana/id.json"
19+
20+
[scripts]
21+
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[workspace]
2+
members = [
3+
"programs/*"
4+
]
5+
resolver = "2"
6+
7+
[profile.release]
8+
overflow-checks = true
9+
lto = "fat"
10+
codegen-units = 1
11+
[profile.release.build-override]
12+
opt-level = 3
13+
incremental = false
14+
codegen-units = 1
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"scripts": {
3+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5+
},
6+
"dependencies": {
7+
"@coral-xyz/anchor": "^0.30.1",
8+
"@metaplex-foundation/mpl-token-metadata": "^3.1.2",
9+
"@metaplex-foundation/umi": "^0.9.0",
10+
"@solana/spl-token": "^0.4.6",
11+
"axios": "^1.6.7",
12+
"node-fetch": "^3.3.2"
13+
},
14+
"devDependencies": {
15+
"@types/bn.js": "^5.1.0",
16+
"@types/chai": "^4.3.0",
17+
"@types/mocha": "^9.0.0",
18+
"chai": "^4.3.4",
19+
"mocha": "^9.0.3",
20+
"prettier": "^2.6.2",
21+
"ts-mocha": "^10.0.0",
22+
"typescript": "^4.3.5"
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "mint-nft"
3+
version = "0.1.0"
4+
description = "Created with Anchor"
5+
edition = "2021"
6+
7+
[lib]
8+
crate-type = ["cdylib", "lib"]
9+
name = "mint_nft"
10+
11+
[features]
12+
no-entrypoint = []
13+
no-idl = []
14+
no-log-ix-name = []
15+
cpi = ["no-entrypoint"]
16+
default = []
17+
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
18+
19+
[dependencies]
20+
anchor-lang = { version = "0.30.1", features = ["init-if-needed"] }
21+
anchor-spl = { version = "0.30.1", features = ["metadata"] }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.bpfel-unknown-unknown.dependencies.std]
2+
features = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use anchor_lang::prelude::*;
2+
use anchor_spl::{
3+
associated_token::AssociatedToken,
4+
metadata::Metadata,
5+
token::{
6+
mint_to,
7+
Mint,
8+
MintTo,
9+
Token,
10+
TokenAccount,
11+
}
12+
};
13+
use anchor_spl::metadata::mpl_token_metadata::{
14+
instructions::{
15+
CreateMasterEditionV3Cpi,
16+
CreateMasterEditionV3CpiAccounts,
17+
CreateMasterEditionV3InstructionArgs,
18+
CreateMetadataAccountV3Cpi,
19+
CreateMetadataAccountV3CpiAccounts,
20+
CreateMetadataAccountV3InstructionArgs
21+
},
22+
types::{
23+
CollectionDetails,
24+
Creator,
25+
DataV2
26+
}
27+
};
28+
29+
#[derive(Accounts)]
30+
pub struct CreateCollection<'info> {
31+
#[account(mut)]
32+
user: Signer<'info>,
33+
#[account(
34+
init,
35+
payer = user,
36+
mint::decimals = 0,
37+
mint::authority = mint_authority,
38+
mint::freeze_authority = mint_authority,
39+
)]
40+
mint: Account<'info, Mint>,
41+
#[account(
42+
seeds = [b"authority"],
43+
bump,
44+
)]
45+
/// CHECK: This account is not initialized and is being used for signing purposes only
46+
pub mint_authority: UncheckedAccount<'info>,
47+
#[account(mut)]
48+
/// CHECK: This account will be initialized by the metaplex program
49+
metadata: UncheckedAccount<'info>,
50+
#[account(mut)]
51+
/// CHECK: This account will be initialized by the metaplex program
52+
master_edition: UncheckedAccount<'info>,
53+
#[account(
54+
init,
55+
payer = user,
56+
associated_token::mint = mint,
57+
associated_token::authority = user
58+
)]
59+
destination: Account<'info, TokenAccount>,
60+
system_program: Program<'info, System>,
61+
token_program: Program<'info, Token>,
62+
associated_token_program: Program<'info, AssociatedToken>,
63+
token_metadata_program: Program<'info, Metadata>,
64+
}
65+
66+
impl<'info> CreateCollection<'info> {
67+
pub fn create_collection(&mut self, bumps: &CreateCollectionBumps) -> Result<()> {
68+
69+
let metadata = &self.metadata.to_account_info();
70+
let master_edition = &self.master_edition.to_account_info();
71+
let mint = &self.mint.to_account_info();
72+
let authority = &self.mint_authority.to_account_info();
73+
let payer = &self.user.to_account_info();
74+
let system_program = &self.system_program.to_account_info();
75+
let spl_token_program = &self.token_program.to_account_info();
76+
let spl_metadata_program = &self.token_metadata_program.to_account_info();
77+
78+
let seeds = &[
79+
&b"authority"[..],
80+
&[bumps.mint_authority]
81+
];
82+
let signer_seeds = &[&seeds[..]];
83+
84+
let cpi_program = self.token_program.to_account_info();
85+
let cpi_accounts = MintTo {
86+
mint: self.mint.to_account_info(),
87+
to: self.destination.to_account_info(),
88+
authority: self.mint_authority.to_account_info(),
89+
};
90+
let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds);
91+
mint_to(cpi_ctx, 1)?;
92+
msg!("Collection NFT minted!");
93+
94+
let creator = vec![
95+
Creator {
96+
address: self.mint_authority.key().clone(),
97+
verified: true,
98+
share: 100,
99+
},
100+
];
101+
102+
let metadata_account = CreateMetadataAccountV3Cpi::new(
103+
spl_metadata_program,
104+
CreateMetadataAccountV3CpiAccounts {
105+
metadata,
106+
mint,
107+
mint_authority: authority,
108+
payer,
109+
update_authority: (authority, true),
110+
system_program,
111+
rent: None,
112+
},
113+
CreateMetadataAccountV3InstructionArgs {
114+
data: DataV2 {
115+
name: "DummyCollection".to_owned(),
116+
symbol: "DC".to_owned(),
117+
uri: "".to_owned(),
118+
seller_fee_basis_points: 0,
119+
creators: Some(creator),
120+
collection: None,
121+
uses: None,
122+
},
123+
is_mutable: true,
124+
collection_details: Some(
125+
CollectionDetails::V1 {
126+
size: 0
127+
}
128+
)
129+
}
130+
);
131+
metadata_account.invoke_signed(signer_seeds)?;
132+
msg!("Metadata Account created!");
133+
134+
let master_edition_account = CreateMasterEditionV3Cpi::new(
135+
spl_metadata_program,
136+
CreateMasterEditionV3CpiAccounts {
137+
edition: master_edition,
138+
update_authority: authority,
139+
mint_authority: authority,
140+
mint,
141+
payer,
142+
metadata,
143+
token_program: spl_token_program,
144+
system_program,
145+
rent: None,
146+
},
147+
CreateMasterEditionV3InstructionArgs {
148+
max_supply: Some(0),
149+
}
150+
);
151+
master_edition_account.invoke_signed(signer_seeds)?;
152+
msg!("Master Edition Account created");
153+
154+
Ok(())
155+
}
156+
}

0 commit comments

Comments
 (0)