Solana 中代币的交互

  • nilliol
  • 更新于 2024-08-10 17:54
  • 阅读 1208

这里主要就是通过程序发行的代币相关的交互。SPL(ERC20)代币的交互在Solana中,可以官方提供了模板进行山寨币的创建,可以通过调用系统程序进行代币的创建。JS交互可以通过JS和SPL代币进行交互,包括了:代币的创建、铸币、查看账户中代币的余额、进行SPL代币转账、销毁持有的SPL

这里主要就是通过程序发行的代币相关的交互。

SPL(ERC20)代币的交互

Solana中,可以官方提供了模板进行山寨币的创建,可以通过调用系统程序进行代币的创建。

JS 交互

可以通过JSSPL代币进行交互,包括了:代币的创建、铸币、查看账户中代币的余额、进行SPL代币转账、销毁持有的SPL

// 通过 js 创建 spl 、查看 spl 余额、进行 spl 转账、销毁 spl

// 导入相关模块
const web3 = require("@solana/web3.js");
const spltoken = require("@solana/spl-token");

// 创建与 solana 的连接
const connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

// 加载钱包文件
function localwalletkey(keypairFile) {
    const fs = require("fs");
    const loaded = web3.Keypair.fromSecretKey(
        new Uint8Array(JSON.parse(fs.readFileSync(keypairFile).toString()))
    );
    return loaded;
}

// 创建一个 spl token
async function createspl() {
    // 加载一个钱包,作为交易费用支付者
    const pairkey = localwalletkey("$key_path");

    ////////////////// 创建中涉及的用户地址 //////////////////
    // 交易费用支付者
    const payer = pairkey;
    // 控制铸币的账户
    const mintAuthority = pairkey.publicKey;
    // 可以冻结代币的账户(可选是否存在)
    const freezeAuthority = pairkey.publicKey;

    // 通过solana系统程序创建一个 spl 代币
    const mint = await spltoken.createMint(
        // solana 连接
        connection,
        payer,
        mintAuthority,
        freezeAuthority,
        // 代币的精度
        9
    );
    console.log("创建新SPLToken", mint.toBase58());
}

// 向指定账户进行铸币
async function minttoken(account) {
    // 需要铸币的 spl token 地址
    const mint = new web3.PublicKey("token_address");
    // 支付交易费用者
    const payer = localwalletkey("$key_path");
    // 拥有铸币权限的地址(因为是测试,所以地址为 payer)
    const mintAuthority = payer;
    // 接收 spl token 的地址
    const recipient = account;

    // 获取接收者对应的 token 账户(获取或创建)

    const totokenaccount = await spltoken.getOrCreateAssociatedTokenAccount(
        connection,
        // 如果要创建账户,那么创建账户交易的支付者
        payer,
        // token 账户对应 token
        mint,
        // 账户的所有者地址
        recipient
    );

    await spltoken.mintTo(
        connection,
        // 交易费用支付者
        payer,
        // token 地址
        mint,
        // 接收者 token 账户地址
        totokenaccount.address,
        // 拥有铸币权限的地址
        mintAuthority.publicKey,
        100 * 1000000000
    );
}

// 查看指定账户的 spl 余额
async function catbalance(account) {
    // 需要监控的地址
    const destination = account;
    // token 地址
    const mint = new web3.PublicKey("token_address");
    const mintinfo = await spltoken.getMint(connection, mint);

    // 获取地址对应的 token 账户
    const splaccount = await spltoken.getAssociatedTokenAddress(mint, destination, true);

    const accountinfo = await spltoken.getAccount(connection, splaccount);
    console.log("token supply:", mintinfo.supply);
    console.log("account address:", account.toBase58());
    console.log("token account Balance:", accountinfo.amount);
}

// 向指定账户转账 spl
async function transferspl() {
    // token 地址
    mint = new web3.PublicKey("token_address");
    // 交易费用支付者
    const payer = localwalletkey("$key_path");

    // 发送者公钥地址
    const sender = payer.publicKey;
    const recipient = new web3.PublicKey("$another_publikey")

    const fromtoken = await spltoken.getAssociatedTokenAddress(mint, sender, true);
    const totoken = await spltoken.getOrCreateAssociatedTokenAccount(
        connection,
        payer,
        mint,
        // 账户的所有者地址
        recipient
    );

    let tx = spltoken.createTransferInstruction(
        fromtoken,
        totoken.address,
        sender,
        1 * 1000000000,
        [],
        spltoken.TOKEN_PROGRAM_ID
    );

    let transaction = new web3.Transaction().add(tx);
    let signature = await web3.sendAndConfirmTransaction(connection, transaction, [payer]);
    console.log("交易哈希:", signature);
}

// 销毁持有的一定数量的 spl 代币
async function burnspl(account) {
    // 交易费用支付者
    const payer = account;
    // token 地址
    const mint = new web3.PublicKey("token_address");
    // 获取地址对应的 token 账户
    const splaccount = await spltoken.getAssociatedTokenAddress(mint, account.publicKey, true);

    let tx = spltoken.createBurnInstruction(splaccount, mint, account.publicKey, 0.1 * 1000000000);
    let transaction = new web3.Transaction().add(tx);
    let signature = await web3.sendAndConfirmTransaction(connection, transaction, [payer]);
    console.log("交易哈希:", signature);
}

async function main() {
    // await createspl();

    const accounta = localwalletkey("wallet-keypair.json");
    const publicKeya = accounta.publicKey;
    const publicKeyb = new web3.PublicKey("BGCmiwDbQ4BDq2vjLARuZ5ptZeXR2BLFB53wmmPpUQyA");

    // 向地址 a 进行铸币
    await minttoken(publicKeya);

    // 查看 a 余额
    await catbalance(publicKeya);

    // a 向 b 转账
    await transferspl();

    // 查看 a 和 b 的余额
    await catbalance(publicKeya);
    await catbalance(publicKeyb);

    await catbalance(publicKeya);

    // 销毁 a 中的一定数量的 spl 代币
    await burnspl(accounta);

    await catbalance(publicKeya);
}

main();

Python 交互

python 的Seahorse很多资料没有,目前只能进行:查看 token 余额、转账

from seahorse.prelude import *
# 在程序中查看 token 余额、转账
declare_id("")

class Program(Account):
    # 进行转账的 spl token 的地址
    mint_addr:Pubkey
    # 存放 spl token 的账户
    program_token_account:Pubkey

@instruction
def init_token_accout(token_account:Empty[TokenAccount],mint:TokenMint,signer:Signer,program:Empty[Program]):
    # 初始化程序的 token account
    token_account = token_account.init(payer=signer,seeds=['token_account'],mint=mint,authority=signer)

    # 初始化并保存程序的账户
    program = program.init(payer=signer,seeds=['program'])
    program.mint_addr = mint.key()
    program.program_token_account = token_account.key()

# 将自己手中的 spl token 发送给程序的 token 账户
@instruction
def spend_token(spender_token:TokenAccount,program_token_account:TokenAccount,signer:Signer,program:Program):
    # 检查用户提供的 spl token 是不是我们指定的 spl token
    assert str(spender_token.mint) == str(program.mint_addr),"token error"

    # 保证发送到的 token 账户,为指定的 token 账户
    assert program_token_account.key() == program.program_token_account,"program token account error"

    spender_token.transfer(authority=signer,to=program_token_account,amount=10000000)

# 取出程序中的 spl token
@instruction
def withdrawals(to_account:TokenAccount,program_token_account:TokenAccount,program:Program,signer:Signer):
    # 检查用户提供的 spl token 是不是我们指定的 spl token
    assert str(to_account.mint) == str(program.mint_addr),"token error"

    # 保证取出的 token 账户,为指定的 token 账户
    assert program_token_account.key() == program.program_token_account,"program token account error"

    # 将程序的 token 账户中的所有余额取出
    program_token_account.transfer(authority=signer,to=to_account,amount=u64(program_token_account.amount))

NFT 代币的交互

Solana中铸造一个 NFT 其实就是铸造一个特殊的SPL代币,精度为 0,数量为1,该token带有的metadata和普通SPL有些不同。

在前面的SPL的声明中,并没有输入token的名称的信息,

JS 交互

因为NFTSPL相差不多,主要区别在于声明参数,和必须添加metadata部分(SPL可以不添加,这样只是会显得这个SPL没有特点,添加的话和NFT几乎一样的方法,只是属性略有区别),所以只列举了NFT的创建。

// 导入相关库
const { createMetadataAccountV3 } = require("@metaplex-foundation/mpl-token-metadata");
const { createSignerFromKeypair, none, signerIdentity } = require("@metaplex-foundation/umi");
const { createUmi } = require("@metaplex-foundation/umi-bundle-defaults");
const {
    fromWeb3JsKeypair,
    fromWeb3JsPublicKey,
} = require("@metaplex-foundation/umi-web3js-adapters");
const web3 = require("@solana/web3.js");
const { create } = require("domain");

// 加载钱包文件
function localwalletkey(keypairFile) {
    const fs = require("fs");
    const loaded = web3.Keypair.fromSecretKey(
        new Uint8Array(JSON.parse(fs.readFileSync(keypairFile).toString()))
    );
    return loaded;
}

async function creatNft() {
    /////////////////////// 环境准备 ///////////////////////
    // 加载钱包
    const mywallet = localwalletkey("$key_path");

    // 创建的 spl token 的地址(spl 的精度为 0 ,数量为 1)
    const mint = new web3.PublicKey("token addr");

    // 创建与 solana 连接实例
    const umi = createUmi("https://api.devnet.solana.com");

    // 使用现有钱包生成一个签名对象,方便签名交易
    const signer = createSignerFromKeypair(umi, fromWeb3JsKeypair(mywallet));
    // 设置 umi
    umi.use(signerIdentity(signer, true));

    /////////////////////// 数据准备 ///////////////////////

    // 创建 NFT 的数据内容
    const nftMetadata = {
        name: "NFT name",
        symbol: "TN",
        // 存储在链下,但是其他地方如 ipfs 上所得到的地址
        uri: "json uri",
        sellerFeeBasisPoints: 0,
        creators: none(),
        collection: none(),
        uses: none(),
    };

    const accounts = {
        mint: fromWeb3JsPublicKey(mint),
        mintAuthority: signer,
    };

    const data = {
        isMutable: true,
        colletionDetails: null,
        data: nftMetadata,
    };

    /////////////////////// 上链 ///////////////////////
    // 将数据上链
    const txid = await createMetadataAccountV3(umi, { ...accounts, ...data }).sendAndConfirm(umi);
}

creatNft();
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
nilliol
nilliol
0xbe3e...29A9
web3 的学习者,寻找实习机会中。 博客地址:https://llwh2333.github.io