Solana에서 NFT를 만드는 방법
Last updated June 18, 2024
이것은 Metaplex Token Metadata 프로토콜을 사용하여 Solana 블록체인에서 NFT를 만드는 방법에 대한 초기 가이드입니다.
전제조건
- 선택한 코드 에디터 (Visual Studio Code 권장)
- Node 18.x.x 이상.
초기 설정
이 가이드는 단일 파일 스크립트를 기반으로 한 Javascript를 사용한 NFT 생성을 다룹니다. 필요에 따라 함수를 수정하고 이동해야 할 수 있습니다.
초기화
선택한 패키지 매니저(npm, yarn, pnpm, bun)로 새 프로젝트를 초기화하고(선택사항) 프롬프트가 나타나면 필요한 세부 정보를 입력하여 시작하세요.
npm init
필수 패키지
이 가이드에 필요한 패키지를 설치하세요.
1import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
2import { generateSigner, percentAmount } from '@metaplex-foundation/umi';
3import {
4 mplTokenMetadata,
5 createNft,
6 fetchDigitalAsset,
7} from '@metaplex-foundation/mpl-token-metadata';
8
9// Create Umi instance with the Token Metadata plugin
10const umi = createUmi('https://api.devnet.solana.com')
11 .use(mplTokenMetadata());
12
13// Connect your wallet (keypair or wallet adapter)
14// For keypair: umi.use(keypairIdentity(keypair))
15// For wallet adapter: umi.use(walletAdapterIdentity(wallet))
16
17// Generate a new mint keypair
18const mint = generateSigner(umi);
19
20// Create an NFT
21await createNft(umi, {
22 mint,
23 name: 'My NFT',
24 uri: 'https://example.com/my-nft.json',
25 sellerFeeBasisPoints: percentAmount(5.5),
26}).sendAndConfirm(umi);
27
28// Fetch the NFT data
29const asset = await fetchDigitalAsset(umi, mint.publicKey);
30
31console.log('NFT created successfully!');
32console.log('Mint address:', mint.publicKey);
33console.log('Name:', asset.metadata.name);
34console.log('URI:', asset.metadata.uri);
1import {
2 appendTransactionMessageInstructions,
3 createSolanaRpc,
4 createSolanaRpcSubscriptions,
5 createTransactionMessage,
6 generateKeyPairSigner,
7 getSignatureFromTransaction,
8 type Instruction,
9 type TransactionSigner,
10 pipe,
11 sendAndConfirmTransactionFactory,
12 setTransactionMessageFeePayer,
13 setTransactionMessageLifetimeUsingBlockhash,
14 signTransactionMessageWithSigners,
15} from '@solana/kit';
16import {
17 createNft,
18 fetchDigitalAsset,
19} from '@metaplex-foundation/mpl-token-metadata-kit';
20
21// Create RPC connection
22const rpc = createSolanaRpc('https://api.devnet.solana.com');
23const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.devnet.solana.com');
24
25// Generate keypairs (or load from wallet)
26const authority = await generateKeyPairSigner();
27const mint = await generateKeyPairSigner();
28
29// Helper function to send and confirm transactions
30// Works with any signer type - signers are automatically extracted from instruction accounts
31async function sendAndConfirm(options: {
32 instructions: Instruction[];
33 payer: TransactionSigner;
34}) {
35 const { instructions, payer } = options;
36 const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
37
38 const transactionMessage = pipe(
39 createTransactionMessage({ version: 0 }),
40 (tx) => setTransactionMessageFeePayer(payer.address, tx),
41 (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
42 (tx) => appendTransactionMessageInstructions(instructions, tx),
43 );
44
45 // Sign with all signers attached to instruction accounts
46 const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
47
48 const sendAndConfirmTx = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
49 await sendAndConfirmTx(signedTransaction, { commitment: 'confirmed' });
50
51 return getSignatureFromTransaction(signedTransaction);
52}
53
54// Create and mint an NFT using the helper function
55const [createIx, mintIx] = await createNft({
56 mint,
57 authority,
58 payer: authority,
59 name: 'My NFT',
60 uri: 'https://example.com/my-nft.json',
61 sellerFeeBasisPoints: 550, // 5.5%
62 tokenOwner: authority.address,
63});
64
65// Send transaction
66const sx = await sendAndConfirm({
67 instructions: [createIx, mintIx],
68 payer: authority,
69});
70
71// Fetch the NFT data
72const asset = await fetchDigitalAsset(rpc, mint.address);
73
74console.log('NFT created successfully!');
75console.log('Mint address:', mint.address);
76console.log('Signature:', sx);
77console.log('Name:', asset.metadata.name);
78console.log('URI:', asset.metadata.uri);
SDK 설정
1import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
2import { generateSigner, percentAmount } from '@metaplex-foundation/umi';
3import {
4 mplTokenMetadata,
5 createNft,
6 fetchDigitalAsset,
7} from '@metaplex-foundation/mpl-token-metadata';
8
9// Create Umi instance with the Token Metadata plugin
10const umi = createUmi('https://api.devnet.solana.com')
11 .use(mplTokenMetadata());
12
13// Connect your wallet (keypair or wallet adapter)
14// For keypair: umi.use(keypairIdentity(keypair))
15// For wallet adapter: umi.use(walletAdapterIdentity(wallet))
16
17// Generate a new mint keypair
18const mint = generateSigner(umi);
19
20// Create an NFT
21await createNft(umi, {
22 mint,
23 name: 'My NFT',
24 uri: 'https://example.com/my-nft.json',
25 sellerFeeBasisPoints: percentAmount(5.5),
26}).sendAndConfirm(umi);
27
28// Fetch the NFT data
29const asset = await fetchDigitalAsset(umi, mint.publicKey);
30
31console.log('NFT created successfully!');
32console.log('Mint address:', mint.publicKey);
33console.log('Name:', asset.metadata.name);
34console.log('URI:', asset.metadata.uri);
1import {
2 appendTransactionMessageInstructions,
3 createSolanaRpc,
4 createSolanaRpcSubscriptions,
5 createTransactionMessage,
6 generateKeyPairSigner,
7 getSignatureFromTransaction,
8 type Instruction,
9 type TransactionSigner,
10 pipe,
11 sendAndConfirmTransactionFactory,
12 setTransactionMessageFeePayer,
13 setTransactionMessageLifetimeUsingBlockhash,
14 signTransactionMessageWithSigners,
15} from '@solana/kit';
16import {
17 createNft,
18 fetchDigitalAsset,
19} from '@metaplex-foundation/mpl-token-metadata-kit';
20
21// Create RPC connection
22const rpc = createSolanaRpc('https://api.devnet.solana.com');
23const rpcSubscriptions = createSolanaRpcSubscriptions('wss://api.devnet.solana.com');
24
25// Generate keypairs (or load from wallet)
26const authority = await generateKeyPairSigner();
27const mint = await generateKeyPairSigner();
28
29// Helper function to send and confirm transactions
30// Works with any signer type - signers are automatically extracted from instruction accounts
31async function sendAndConfirm(options: {
32 instructions: Instruction[];
33 payer: TransactionSigner;
34}) {
35 const { instructions, payer } = options;
36 const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
37
38 const transactionMessage = pipe(
39 createTransactionMessage({ version: 0 }),
40 (tx) => setTransactionMessageFeePayer(payer.address, tx),
41 (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
42 (tx) => appendTransactionMessageInstructions(instructions, tx),
43 );
44
45 // Sign with all signers attached to instruction accounts
46 const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
47
48 const sendAndConfirmTx = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
49 await sendAndConfirmTx(signedTransaction, { commitment: 'confirmed' });
50
51 return getSignatureFromTransaction(signedTransaction);
52}
53
54// Create and mint an NFT using the helper function
55const [createIx, mintIx] = await createNft({
56 mint,
57 authority,
58 payer: authority,
59 name: 'My NFT',
60 uri: 'https://example.com/my-nft.json',
61 sellerFeeBasisPoints: 550, // 5.5%
62 tokenOwner: authority.address,
63});
64
65// Send transaction
66const sx = await sendAndConfirm({
67 instructions: [createIx, mintIx],
68 payer: authority,
69});
70
71// Fetch the NFT data
72const asset = await fetchDigitalAsset(rpc, mint.address);
73
74console.log('NFT created successfully!');
75console.log('Mint address:', mint.address);
76console.log('Signature:', sx);
77console.log('Name:', asset.metadata.name);
78console.log('URI:', asset.metadata.uri);
NFT 생성
이미지 업로드
가장 먼저 해야 할 일은 NFT를 나타내고 인식 가능하게 만드는 이미지를 업로드하는 것입니다. 이것은 jpeg, png 또는 gif 형태일 수 있습니다.
Umi는 Arweave, NftStorage, AWS, ShdwDrive와 같은 스토리지 솔루션에 업로드할 수 있는 다운로드 가능한 스토리지 플러그인과 함께 제공됩니다. 이 가이드의 시작 부분에서 Arweave 블록체인에 콘텐츠를 저장하는 irysUploader() 플러그인을 설치했습니다.
로컬 스크립트/Node.js
이 예제는 Irys를 사용하여 Arweave에 업로드하는 로컬 스크립트/node.js 접근 방식을 사용합니다. 다른 스토리지 제공업체에 파일을 업로드하거나 브라우저에서 업로드하려면 다른 접근 방식을 취해야 합니다. 브라우저 시나리오에서는 fs를 가져와서 사용하는 것이 작동하지 않습니다.
Error: Could not load example "token-metadata/upload-assets"
Make sure the file exists at: src/examples/token-metadata/upload-assets/index.js
Cannot find module './token-metadata/upload-assets/index.js'
메타데이터 업로드
유효하고 작동하는 이미지 URI를 얻으면 NFT의 메타데이터 작업을 시작할 수 있습니다.
오프체인 메타데이터의 표준은 다음과 같습니다:
{
"name": "My NFT",
"description": "This is an NFT on Solana",
"image": "https://arweave.net/my-image",
"external_url": "https://example.com/my-nft.json",
"attributes": [
{
"trait_type": "trait1",
"value": "value1"
},
{
"trait_type": "trait2",
"value": "value2"
}
],
"properties": {
"files": [
{
"uri": "https://arweave.net/my-image",
"type": "image/png"
}
],
"category": "image"
}
}
필드 설명:
name
토큰의 이름.
symbol
토큰의 약어. Solana의 약어는 SOL입니다.
description
토큰의 설명.
image
이전에 업로드한 imageUri(또는 이미지의 온라인 위치)로 설정됩니다.
NFT vs pNFT
Token Metadata 프로그램은 일반 NFT와 pNFT(프로그래머블 Non-Fungible Asset) 두 가지 종류의 NFT를 민팅할 수 있습니다. 두 유형의 NFT 간의 주요 차이점은 하나는 로열티가 강제되고(pNFT) 다른 하나는 그렇지 않다는 것입니다(NFT).
NFT
- 로열티 강제 없음
- 초기 설정이 더 간단하고 향후 작업이 더 쉬움
pNFT
- 향후 개발과 관련하여 더 많은 계정을 다뤄야 함
- 로열티 강제
- 프로그래머블 - 프로그램이 전송을 차단할 수 있는 규칙 세트가 있음
NFT 민팅
여기에서 사용하려는 NFT 민트 명령어 유형(NFT 또는 pNFT)을 선택할 수 있습니다.
NFT
1import { percentAmount, generateSigner } from '@metaplex-foundation/umi';
2import { createNft } from '@metaplex-foundation/mpl-token-metadata';
3
4// Assuming umi is set up with mplTokenMetadata plugin
5// See getting-started for full setup
6
7const mint = generateSigner(umi);
8
9// Create and mint an NFT in one step
10await createNft(umi, {
11 mint,
12 name: 'My NFT',
13 uri: 'https://example.com/my-nft.json',
14 sellerFeeBasisPoints: percentAmount(5.5),
15 // Optional: add to collection (must verify separately)
16 // collection: some({ key: collectionMint.publicKey, verified: false }),
17}).sendAndConfirm(umi);
18
19console.log('NFT created:', mint.publicKey);
1import { generateKeyPairSigner } from '@solana/kit';
2import { createNft } from '@metaplex-foundation/mpl-token-metadata-kit';
3
4// Assuming rpc, rpcSubscriptions, and sendAndConfirmInstructions are set up
5// See getting-started for full setup
6
7const mint = await generateKeyPairSigner();
8const authority = await generateKeyPairSigner(); // Your wallet
9
10// Create and mint an NFT in one step
11const [createIx, mintIx] = await createNft({
12 mint,
13 authority,
14 payer: authority,
15 name: 'My NFT',
16 uri: 'https://example.com/my-nft.json',
17 sellerFeeBasisPoints: 550, // 5.5%
18 tokenOwner: authority.address,
19 // Optional: add to collection (must verify separately)
20 // collection: { key: collectionMint.address, verified: false },
21});
22
23// Send both instructions in one transaction
24await sendAndConfirm({
25 instructions: [createIx, mintIx],
26 payer: authority,
27});
28
29console.log('NFT created:', mint.address);
pNFT
1import { percentAmount, generateSigner } from '@metaplex-foundation/umi';
2import { createProgrammableNft } from '@metaplex-foundation/mpl-token-metadata';
3
4// Assuming umi is set up with mplTokenMetadata plugin
5
6const mint = generateSigner(umi);
7
8// Create and mint a Programmable NFT in one step
9await createProgrammableNft(umi, {
10 mint,
11 name: 'My Programmable NFT',
12 uri: 'https://example.com/my-programmable-nft.json',
13 sellerFeeBasisPoints: percentAmount(5.5),
14 // Optional: add to collection (must verify separately)
15 // collection: some({ key: collectionMint.publicKey, verified: false }),
16}).sendAndConfirm(umi);
17
18console.log('Programmable NFT created:', mint.publicKey);
1import { generateKeyPairSigner } from '@solana/kit';
2import { createProgrammableNft } from '@metaplex-foundation/mpl-token-metadata-kit';
3
4// Assuming rpc, rpcSubscriptions, and sendAndConfirmInstructions are set up
5
6const mint = await generateKeyPairSigner();
7const authority = await generateKeyPairSigner(); // Your wallet
8
9// Create and mint a Programmable NFT in one step
10const [createIx, mintIx] = await createProgrammableNft({
11 mint,
12 authority,
13 payer: authority,
14 name: 'My Programmable NFT',
15 uri: 'https://example.com/my-programmable-nft.json',
16 sellerFeeBasisPoints: 550, // 5.5%
17 tokenOwner: authority.address,
18 // Optional: add to collection (must verify separately)
19 // collection: { key: collectionMint.address, verified: false },
20});
21
22// Send both instructions in one transaction
23await sendAndConfirm({
24 instructions: [createIx, mintIx],
25 payer: authority,
26});
27
28console.log('Programmable NFT created:', mint.address);
다음 단계
이 가이드는 기본 NFT를 만드는 데 도움이 되었습니다. 여기에서 Token Metadata 프로그램으로 이동하여 컬렉션 만들기, 새 NFT를 컬렉션에 추가하기, NFT로 수행할 수 있는 다양한 기타 상호 작용을 확인할 수 있습니다.
