目录
1.空投和转账概念
1.1.空投(Airdrop)
- 创建新代币: 空投是铸造(Mint)新代币并直接分发到接收者的钱包
- 增加总供应量: 每次空投都会增加代币的总流通量
- 需要特殊权限: 只有拥有代币铸造权限(Mint Authority)的账户才能执行空投
- 指令类型: 使用
createMintToInstruction
指令
1.2.转账(Transfer)
- 移动现有代币: 转账只是将已存在的代币从一个账户移动到另一个账户
- 不改变总供应量: 转账不会影响代币的总流通量
- 普通权限: 任何持有代币的人都可以进行转账
- 指令类型: 使用
createTransferInstruction
指令
2.Solana 代币创建与空投核心代码总结
2.1. 代币创建核心代码
// 生成代币密钥对
const mintKeypair = Keypair.generate();
// 获取最小租金豁免金额
const lamports = await getMinimumBalanceForRentExemptMint(connection);
// 创建代币指令
const tokenInstructions = [
// 创建Mint账户
SystemProgram.createAccount({
fromPubkey: publicKey, // 用户钱包
newAccountPubkey: mintKeypair.publicKey,
space: MINT_SIZE,
lamports,
programId: TOKEN_PROGRAM_ID,
}),
// 初始化Mint
createInitializeMint2Instruction(
mintKeypair.publicKey,
tokenDecimals, // 代币小数位数
publicKey, // Mint权限
publicKey, // Freeze权限
TOKEN_PROGRAM_ID
)
];
// 创建并发送交易
const transaction = new Transaction().add(...tokenInstructions);
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
const signature = await sendTransaction(transaction, connection, {
signers: [mintKeypair],
});
// 等待确认
await connection.confirmTransaction({signature}, 'confirmed');
2.2. 添加元数据核心代码
// 获取元数据账户地址
const metadataPDA = getMetadataPDA(mintKeypair.publicKey);
// 创建元数据指令
const metadataInstruction = createCreateMetadataInstruction(
metadataPDA,
mintKeypair.publicKey,
publicKey, // 授权者
publicKey, // 支付者
publicKey, // 更新权限
tokenName, // 代币名称
tokenSymbol, // 代币符号
tokenURI // 元数据URI
);
// 发送元数据交易
const transaction = new Transaction().add(metadataInstruction);
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
const signature = await sendTransaction(transaction, connection);
await connection.confirmTransaction({signature}, 'confirmed');
2.3. 空投代币核心代码
// 计算代币数量(考虑小数位)
const tokenAmount = BigInt(Math.floor(airdropAmount * (10 ** tokenDecimals)));
// 分批处理地址(每批5个)
const batchSize = 5;
for (let i = 0; i < validAddresses.length; i += batchSize) {
const batch = validAddresses.slice(i, i + batchSize);
const instructions = [];
// 处理每个地址
for (const address of batch) {
// 获取关联代币账户地址
const ataAccount = getAssociatedTokenAddressSync(
mintKeyPair.publicKey,
address,
false,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
// 检查账户是否存在,不存在则创建
try {
await getAccount(connection, ataAccount);
} catch (err) {
instructions.push(
createAssociatedTokenAccountInstruction(
publicKey,
ataAccount,
address,
mintKeyPair.publicKey,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
)
);
}
// 添加铸币指令
instructions.push(
createMintToInstruction(
mintKeyPair.publicKey,
ataAccount,
publicKey,
tokenAmount,
[],
TOKEN_PROGRAM_ID
)
);
}
// 发送交易
const transaction = new Transaction().add(...instructions);
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
const signature = await sendTransaction(transaction, connection);
await connection.confirmTransaction({signature}, 'confirmed');
}