当前位置:网站首页>152-Solana入门(十六)- 创建MetaplexNFT
152-Solana入门(十六)- 创建MetaplexNFT
2022-06-21 06:26:00 【Lich Howger】
之前说过
solana中是没有像ERC721这样的nft标准的
现在大家都用Metaplex的nft标准
所以我们来试试看创建MetaplexNFT
我们先来看一下网络上的一个示例
import * as anchor from '@project-serum/anchor'
import { Program, Wallet } from '@project-serum/anchor'
import { MetaplexAnchorNft } from '../target/types/metaplex_anchor_nft'
import { TOKEN_PROGRAM_ID, createAssociatedTokenAccountInstruction, getAssociatedTokenAddress, createInitializeMintInstruction, MINT_SIZE } from '@solana/spl-token' // IGNORE THESE ERRORS IF ANY
const { SystemProgram } = anchor.web3
describe('metaplex-anchor-nft', () => {
// Configure the client to use the local cluster.
const provider = anchor.AnchorProvider.env();
const wallet = provider.wallet as Wallet;
anchor.setProvider(provider);
const program = anchor.workspace.MetaplexAnchorNft as Program<MetaplexAnchorNft>
it("Is initialized!", async () => {
// Add your test here.
const TOKEN_METADATA_PROGRAM_ID = new anchor.web3.PublicKey(
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
);
const lamports: number =
await program.provider.connection.getMinimumBalanceForRentExemption(
MINT_SIZE
);
const getMetadata = async (
mint: anchor.web3.PublicKey
): Promise<anchor.web3.PublicKey> => {
return (
await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
mint.toBuffer(),
],
TOKEN_METADATA_PROGRAM_ID
)
)[0];
};
const getMasterEdition = async (
mint: anchor.web3.PublicKey
): Promise<anchor.web3.PublicKey> => {
return (
await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from("metadata"),
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
mint.toBuffer(),
Buffer.from("edition"),
],
TOKEN_METADATA_PROGRAM_ID
)
)[0];
};
const mintKey: anchor.web3.Keypair = anchor.web3.Keypair.generate();
const NftTokenAccount = await getAssociatedTokenAddress(
mintKey.publicKey,
wallet.publicKey
);
console.log("NFT Account: ", NftTokenAccount.toBase58());
const mint_tx = new anchor.web3.Transaction().add(
anchor.web3.SystemProgram.createAccount({
fromPubkey: wallet.publicKey,
newAccountPubkey: mintKey.publicKey,
space: MINT_SIZE,
programId: TOKEN_PROGRAM_ID,
lamports,
}),
createInitializeMintInstruction(
mintKey.publicKey,
0,
wallet.publicKey,
wallet.publicKey
),
createAssociatedTokenAccountInstruction(
wallet.publicKey,
NftTokenAccount,
wallet.publicKey,
mintKey.publicKey
)
);
const res = await program.provider.sendAndConfirm(mint_tx, [mintKey]);
console.log(
await program.provider.connection.getParsedAccountInfo(mintKey.publicKey)
);
console.log("Account: ", res);
console.log("Mint key: ", mintKey.publicKey.toString());
console.log("User: ", wallet.publicKey.toString());
const metadataAddress = await getMetadata(mintKey.publicKey);
const masterEdition = await getMasterEdition(mintKey.publicKey);
console.log("Metadata address: ", metadataAddress.toBase58());
console.log("MasterEdition: ", masterEdition.toBase58());
const tx = await program.methods.mintNft(
mintKey.publicKey,
"https://arweave.net/y5e5DJsiwH0s_ayfMwYk-SnrZtVZzHLQDSTZ5dNRUHA",
"NFT Title",
)
.accounts({
mintAuthority: wallet.publicKey,
mint: mintKey.publicKey,
tokenAccount: NftTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
metadata: metadataAddress,
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
payer: wallet.publicKey,
systemProgram: SystemProgram.programId,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
masterEdition: masterEdition,
},
)
.rpc();
console.log("Your transaction signature", tx);
});
});这边是前端调用的示例
这边他是先在前端做了3个操作
然后再调用合约的mintNFT
现在我们已经把前3个操作放到了合约里面
现在我们把mintNFT的3个操作和前3个操作结合起来
先是mint_to
我们来看一下
/// Creates a `MintTo` instruction.
pub fn mint_to(
token_program_id: &Pubkey,
mint_pubkey: &Pubkey,
account_pubkey: &Pubkey,
owner_pubkey: &Pubkey,
signer_pubkeys: &[&Pubkey],
amount: u64,
) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let data = TokenInstruction::MintTo { amount }.pack();
let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
accounts.push(AccountMeta::new(*mint_pubkey, false));
accounts.push(AccountMeta::new(*account_pubkey, false));
accounts.push(AccountMeta::new_readonly(
*owner_pubkey,
signer_pubkeys.is_empty(),
));
for signer_pubkey in signer_pubkeys.iter() {
accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
}
Ok(Instruction {
program_id: *token_program_id,
accounts,
data,
})
}那么我们就调用这个指令
msg!("Mint To");
invoke(
&mint_to(
token_program_info.key,
mint_info.key,
ata_info.key,
signer_info.key,
&[signer_info.key],
1,
)?,
&[
signer_info.clone(),
ata_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;然后我们把mint_to和前面3个指令全都合并在一起
这样的话就相当于完成了一系列从无到有
从什么都没有到创建好mint,再mint_to
use borsh::BorshSerialize;
use mpl_token_metadata::instruction::create_master_edition;
use solana_program::{
account_info::{AccountInfo, next_account_info},
entrypoint::ProgramResult,
msg,
program::{invoke, invoke_signed},
program_error::ProgramError,
pubkey::Pubkey,
system_instruction,
sysvar::{clock::Clock, rent::Rent, Sysvar},
};
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token::instruction::{initialize_mint, mint_to};
use crate::{ferror, state::*, utils::*};
pub fn process_mint(
program_id: &Pubkey,
accounts: &[AccountInfo],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let authority_info = next_account_info(account_info_iter)?;
let signer_info = next_account_info(account_info_iter)?;
let mint_info = next_account_info(account_info_iter)?;
let ata_info = next_account_info(account_info_iter)?;
let token_program_info = next_account_info(account_info_iter)?;
let ass_token_program_info = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let system_info = next_account_info(account_info_iter)?;
assert_signer(&signer_info)?;
let size = 82;
let rent = &Rent::from_account_info(&rent_info)?;
let required_lamports = rent.minimum_balance(size);
msg!("Create Account");
invoke(
&system_instruction::create_account(
signer_info.key,
mint_info.key,
required_lamports,
size as u64,
token_program_info.key,
),
&[signer_info.clone(), mint_info.clone()],
)?;
msg!("Initialize Mint");
invoke(
&initialize_mint(
token_program_info.key,
mint_info.key,
authority_info.key,
Some(authority_info.key),
0,
)?,
&[authority_info.clone(), mint_info.clone(), rent_info.clone(), token_program_info.clone(), ],
)?;
msg!("Create Associated Token Account");
invoke(
&create_associated_token_account(
signer_info.key,
signer_info.key,
mint_info.key,
),
&[
signer_info.clone(),
ata_info.clone(),
ass_token_program_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
msg!("Mint To");
invoke(
&mint_to(
token_program_info.key,
mint_info.key,
ata_info.key,
signer_info.key,
&[signer_info.key],
1,
)?,
&[
signer_info.clone(),
ata_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
Ok(())
}
接下来是
create_metadata_account
mint_to之后,我们相当于已经有了一个nft了
但是这个nft只是一个supply为1的普通spl
接下来的两个步骤就是和metaplex相关的了
use borsh::BorshSerialize;
use mpl_token_metadata::instruction::{create_master_edition, create_metadata_accounts_v2};
use solana_program::{
account_info::{AccountInfo, next_account_info},
entrypoint::ProgramResult,
msg,
program::{invoke, invoke_signed},
program_error::ProgramError,
pubkey::Pubkey,
system_instruction,
sysvar::{clock::Clock, rent::Rent, Sysvar},
};
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token::instruction::{initialize_mint, mint_to};
use crate::{ferror, state::*, utils::*};
pub fn process_mint_nft(
program_id: &Pubkey,
accounts: &[AccountInfo],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let authority_info = next_account_info(account_info_iter)?;
let signer_info = next_account_info(account_info_iter)?;
let mint_info = next_account_info(account_info_iter)?;
let ata_info = next_account_info(account_info_iter)?;
let token_program_info = next_account_info(account_info_iter)?;
let ass_token_program_info = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let system_info = next_account_info(account_info_iter)?;
let metadata_program_info = next_account_info(account_info_iter)?;
let metadata_info = next_account_info(account_info_iter)?;
assert_signer(&signer_info)?;
let size = 82;
let rent = &Rent::from_account_info(&rent_info)?;
let required_lamports = rent.minimum_balance(size);
msg!("Create Account");
invoke(
&system_instruction::create_account(
signer_info.key,
mint_info.key,
required_lamports,
size as u64,
token_program_info.key,
),
&[signer_info.clone(), mint_info.clone()],
)?;
msg!("Initialize Mint");
invoke(
&initialize_mint(
token_program_info.key,
mint_info.key,
authority_info.key,
Some(authority_info.key),
0,
)?,
&[authority_info.clone(), mint_info.clone(), rent_info.clone(), token_program_info.clone(), ],
)?;
msg!("Create Associated Token Account");
invoke(
&create_associated_token_account(
signer_info.key,
signer_info.key,
mint_info.key,
),
&[
signer_info.clone(),
ata_info.clone(),
ass_token_program_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
msg!("Mint To");
invoke(
&mint_to(
token_program_info.key,
mint_info.key,
ata_info.key,
signer_info.key,
&[signer_info.key],
1,
)?,
&[
signer_info.clone(),
ata_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
msg!("Create Metadata Account");
let creator = vec![
mpl_token_metadata::state::Creator {
address: *signer_info.key,
verified: false,
share: 100,
},
];
let title = String::from("my_title");
let symbol = String::from("my_symbol");
let uri = String::from("https://arweave.net/abc");
invoke(
&create_metadata_accounts_v2(
*metadata_program_info.key,
*metadata_info.key,
*mint_info.key,
*signer_info.key,
*signer_info.key,
*signer_info.key,
title,
symbol,
uri,
Some(creator),
1,
true,
false,
None,
None,
),
&[
metadata_info.clone(),
mint_info.clone(),
signer_info.clone(),
metadata_program_info.clone(),
token_program_info.clone(),
system_info.clone(),
rent_info.clone(),
],
)?;
Ok(())
}
然后是最后一步
create_master_edition
use borsh::BorshSerialize;
use mpl_token_metadata::instruction::{create_master_edition, create_master_edition_v3, create_metadata_accounts_v2};
use solana_program::{
account_info::{AccountInfo, next_account_info},
entrypoint::ProgramResult,
msg,
program::{invoke, invoke_signed},
program_error::ProgramError,
pubkey::Pubkey,
system_instruction,
sysvar::{clock::Clock, rent::Rent, Sysvar},
};
use spl_associated_token_account::instruction::create_associated_token_account;
use spl_token::instruction::{initialize_mint, mint_to};
use crate::{ferror, state::*, utils::*};
pub fn process_mint_nft_create(
program_id: &Pubkey,
accounts: &[AccountInfo],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let authority_info = next_account_info(account_info_iter)?;
let signer_info = next_account_info(account_info_iter)?;
let mint_info = next_account_info(account_info_iter)?;
let ata_info = next_account_info(account_info_iter)?;
let token_program_info = next_account_info(account_info_iter)?;
let ass_token_program_info = next_account_info(account_info_iter)?;
let rent_info = next_account_info(account_info_iter)?;
let system_info = next_account_info(account_info_iter)?;
let metadata_program_info = next_account_info(account_info_iter)?;
let metadata_info = next_account_info(account_info_iter)?;
let edition_info = next_account_info(account_info_iter)?;
assert_signer(&signer_info)?;
let size = 82;
let rent = &Rent::from_account_info(&rent_info)?;
let required_lamports = rent.minimum_balance(size);
msg!("Create Account");
invoke(
&system_instruction::create_account(
signer_info.key,
mint_info.key,
required_lamports,
size as u64,
token_program_info.key,
),
&[signer_info.clone(), mint_info.clone()],
)?;
msg!("Initialize Mint");
invoke(
&initialize_mint(
token_program_info.key,
mint_info.key,
authority_info.key,
Some(authority_info.key),
0,
)?,
&[authority_info.clone(), mint_info.clone(), rent_info.clone(), token_program_info.clone(), ],
)?;
msg!("Create Associated Token Account");
invoke(
&create_associated_token_account(
signer_info.key,
signer_info.key,
mint_info.key,
),
&[
signer_info.clone(),
ata_info.clone(),
ass_token_program_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
msg!("Mint To");
invoke(
&mint_to(
token_program_info.key,
mint_info.key,
ata_info.key,
signer_info.key,
&[signer_info.key],
1,
)?,
&[
signer_info.clone(),
ata_info.clone(),
mint_info.clone(),
token_program_info.clone(),
system_info.clone()
],
)?;
msg!("Create Metadata Account");
let creator = vec![
mpl_token_metadata::state::Creator {
address: *signer_info.key,
verified: false,
share: 100,
},
];
let title = String::from("my_title");
let symbol = String::from("my_symbol");
let uri = String::from("https://arweave.net/abc");
invoke(
&create_metadata_accounts_v2(
*metadata_program_info.key,
*metadata_info.key,
*mint_info.key,
*signer_info.key,
*signer_info.key,
*signer_info.key,
title,
symbol,
uri,
Some(creator),
1,
true,
false,
None,
None,
),
&[
metadata_info.clone(),
mint_info.clone(),
signer_info.clone(),
metadata_program_info.clone(),
token_program_info.clone(),
system_info.clone(),
rent_info.clone(),
],
)?;
msg!("Create Master Edition");
invoke(
&create_master_edition_v3(
*metadata_program_info.key,
*edition_info.key,
*mint_info.key,
*signer_info.key,
*signer_info.key,
*metadata_info.key,
*signer_info.key,
Some(0),
),
&[
edition_info.clone(),
mint_info.clone(),
signer_info.clone(),
metadata_info.clone(),
metadata_program_info.clone(),
token_program_info.clone(),
system_info.clone(),
rent_info.clone(),
],
)?;
Ok(())
}
然后我们来调用一下
import {Button, StyleSheet, View} from 'react-native';
import * as web3 from "@solana/web3.js";
import {
clusterApiUrl,
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
SystemProgram,
SYSVAR_RENT_PUBKEY,
Transaction,
TransactionInstruction
} from "@solana/web3.js";
import * as bip39 from "bip39";
import * as ed25519 from "ed25519-hd-key";
export default function App() {
return (
<View style={styles.container}>
<Button title="test" onPress={() => test01()}></Button>
</View>
);
}
const test01 = async () => {
// Connect to cluster
var connection = new Connection(
clusterApiUrl('devnet'),
'confirmed',
);
const derivePath = `m/44'/501'/1'/0'`;
const text = 'abc abc abc';
const seed = bip39.mnemonicToSeedSync(text).toString('hex');
const derivedSeed = ed25519.derivePath(derivePath, seed).key;
const wallet = web3.Keypair.fromSeed(derivedSeed);
console.log(wallet.publicKey.toBase58());
const programId = new PublicKey('DfwQ3imRbDKvWQMSeZCrh6c6wQucL4aM1NXE6JWNuNiy')
const mint = Keypair.generate();
const TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
const METADATA_PROGRAM_ID = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
const [ata] = await PublicKey.findProgramAddress(
[
wallet.publicKey.toBuffer(),
TOKEN_PROGRAM_ID.toBuffer(),
mint.publicKey.toBuffer(),
],
ASSOCIATED_TOKEN_PROGRAM_ID
);
console.log("ata:::", ata.toBase58());
const [metadata_info] = await PublicKey.findProgramAddress(
[
Buffer.from("metadata"),
METADATA_PROGRAM_ID.toBuffer(),
mint.publicKey.toBuffer(),
],
METADATA_PROGRAM_ID
);
console.log("metadata:::", metadata_info.toBase58());
const [edition_info] = await PublicKey.findProgramAddress(
[
Buffer.from("metadata"),
METADATA_PROGRAM_ID.toBuffer(),
mint.publicKey.toBuffer(),
Buffer.from("edition"),
],
METADATA_PROGRAM_ID
);
console.log("edition:::", edition_info.toBase58());
const keys = [
{
pubkey: wallet.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: wallet.publicKey,
isSigner: true,
isWritable: true,
},
{
pubkey: mint.publicKey,
isSigner: true,
isWritable: true,
},
{
pubkey: ata,
isSigner: false,
isWritable: true,
},
{
pubkey: TOKEN_PROGRAM_ID,
isSigner: false,
isWritable: false,
},
{
pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
isSigner: false,
isWritable: false,
},
{
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
{
pubkey: METADATA_PROGRAM_ID,
isSigner: false,
isWritable: false,
},
{
pubkey: metadata_info,
isSigner: false,
isWritable: true,
},
{
pubkey: edition_info,
isSigner: false,
isWritable: true,
},
];
const data = Buffer.from([3]);
const initIX = new TransactionInstruction({
keys: keys,
programId: programId,
data,
})
const initTX = new Transaction()
initTX.add(initIX)
const signature = await sendAndConfirmTransaction(
connection,
initTX,
[wallet, mint],
)
console.log("signature::::", signature)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
到此为止,我们的Solana入门系列算是到了一个阶段了
从一开始什么都不懂,什么都学不会
到现在已经熟悉了一些东西
这是一种非常大的进步
虽然过程有一点点艰难
进度也比预想中的慢
但是结果是好的
边栏推荐
- TweenMax示波器3d动画
- File类的构造方法和各种常用的方法
- C语言程序设计——三子棋(学期小作业)
- TweenMax不规则几何图形背景带动画js特效
- Issue 13: Flink zero foundation learning route
- [MySQL] database multi table operation customs clearance tutorial (foreign key constraint, multi table joint query)
- 麦克风loading动画效果
- Chapter 2: Data Model (final review of database)
- 【毕业季】纸短情长,浅谈大二以前的学习经历
- 【MySQL】数据库多表操作通关教程(外键约束、多表联合查询)
猜你喜欢

Deeply understand the gradient disappearance of RNN and why LSTM can solve the gradient disappearance
![[MySQL] database multi table operation customs clearance tutorial (foreign key constraint, multi table joint query)](/img/d9/919687856f0da02f5ae837cb62a4a3.png)
[MySQL] database multi table operation customs clearance tutorial (foreign key constraint, multi table joint query)

太厉害了MySQL总结的太全面了

【MySQL】数据库多表操作通关教程(外键约束、多表联合查询)

Blasting with burp (ordinary blasting + verification code blasting)

Aurora8B10B IP使用 -01- 简介与端口描述

利用burp进行爆破(普通爆破+验证码爆破)

创新项目实训:数据爬取

第8期:云原生—— 大学生职场小白该如何学

Dragon Boat Festival - simple side navigation bar
随机推荐
827. maximum man-made island and collection search
How powerful are spectral graph neural networks
[reproduce ms08-067 via MSF tool intranet]
Docker installing MySQL
Unity隐藏目录和隐藏文件
[JDBC from introduction to actual combat] JDBC basic customs clearance tutorial (comprehensive summary part I)
Aurora8B10B IP使用 -02- IP功能设计技巧
Innovation project training: data analysis and visualization
网格搜索法
Latest analysis on operation of refrigeration and air conditioning equipment in 2022 and examination question bank for operation of refrigeration and air conditioning equipment
Deeply understand the gradient disappearance of RNN and why LSTM can solve the gradient disappearance
Module 14 - 15: network application communication test
Introduction to 3D engine software wizard
Which of the children's critical illness insurance companies has the highest cost performance in 2022?
Survey shows that data analysis is crucial to product success
Contos7 installing SVN server
Is today's mathematics too cumbersome?
PyG教程(2):图数据
Functions and methods in Scala
Memorizing Normality to Detect Anomaly: Memory-augmented Deep Autoencoder for Unsupervised Anomaly D