【Solana】一些基本的js脚本

  • 0xE
  • 更新于 15小时前
  • 阅读 144
  1. 创建账户和查询余额 2. 转账SOL 3. 监听账户余额变化 4. 创建SPLToken 5. SPLToken转账 6. 监听账户的SPLToken的余额变化

本篇文章将介绍 Solana 上的一些基本脚本,包括:

  1. 创建账户和查询余额
  2. 转账 SOL
  3. 监听账户余额变化
  4. 创建 SPL Token
  5. SPL Token 转账
  6. 监听账户的 SPL Token 的余额变化

此外,涉及智能合约交互的脚本将在后续文章中,结合具体合约示例进行讲解。

环境与依赖

本教程使用的依赖和版本如下:

  "dependencies": {
    "@solana/spl-token": "0.4.9",
    "@solana/web3.js": "1.98.0"
  }

如果在运行过程中遇到 网络问题,建议使用代理,并安装 proxychains4

接下来,我们将逐步实现这些功能! 🚀

创建账户和查询余额

创建一个新账户,并且保存在本地。

const web3 = require("@solana/web3.js");
const fs = require("fs");

// 连接到 Solana Devnet
const connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

// 保存私钥到本地文件
function saveWalletKey(keypair, filename) {
    fs.writeFileSync(filename, JSON.stringify(Array.from(keypair.secretKey)));
}

async function main() {
    const walletFile = "id.json";

    // 创建一个新的账户
    const payer = web3.Keypair.generate();
    saveWalletKey(payer, walletFile);
    console.log("新账户创建并保存:", payer.publicKey.toBase58());

    // 查询新账户的余额
    const balance = await connection.getBalance(payer.publicKey);
    console.log("账户余额:", balance / web3.LAMPORTS_PER_SOL, "SOL");
}

main().catch(console.error);

转账 SOL

加载本地的私钥,并且请求空投后,在转出。

const web3 = require('@solana/web3.js');
const fs = require('fs');

// 连接到 Solana Devnet
const connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');

// 从文件加载私钥
function loadWalletKey(filename) {
    const secretKey = JSON.parse(fs.readFileSync(filename).toString());
    return web3.Keypair.fromSecretKey(new Uint8Array(secretKey));
}

async function main() {
    const walletFile = 'id.json';

    const sender = loadWalletKey(walletFile);
    console.log("已加载现有账户:", sender.publicKey.toBase58());

    // 获取账户余额
    let balance = await connection.getBalance(sender.publicKey);
    console.log("当前余额:", balance / web3.LAMPORTS_PER_SOL, "SOL");

    // 请求空投
    const airdropSignature = await connection.requestAirdrop(
        sender.publicKey,
        5 * web3.LAMPORTS_PER_SOL
    );
    await connection.confirmTransaction(airdropSignature, "confirmed");

    // 再次检查余额
    balance = await connection.getBalance(sender.publicKey);
    console.log("空投后余额:", balance / web3.LAMPORTS_PER_SOL, "SOL");

    // 创建收款账户
    const recipient = web3.Keypair.generate();
    console.log("收款账户地址:", recipient.publicKey.toBase58());

    // 构建交易
    const transaction = new web3.Transaction().add(
        web3.SystemProgram.transfer({
            fromPubkey: sender.publicKey,
            toPubkey: recipient.publicKey,
            lamports: web3.LAMPORTS_PER_SOL / 1000, // 0.001 SOL
        })
    );

    // 发送交易
    const signature = await web3.sendAndConfirmTransaction(connection, transaction, [sender]);
    console.log("交易成功!交易签名:", signature);
}

main().catch(console.error);

监听账户余额变化

新建一个账户并监听,可以手动转入 SOL,进行测试。

const web3 = require('@solana/web3.js');

const connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');

async function main() {
    // 创建一个新的账户
    const account = web3.Keypair.generate();
    console.log('正在监听账户:', account.publicKey.toBase58());

    // 监听账户的余额变化
    connection.onAccountChange(account.publicKey,(accountInfo)=>{
        console.log('账户余额更新为:', accountInfo.lamports / web3.LAMPORTS_PER_SOL, 'SOL');
    })

}

main().catch(console.error);

创建 SPL Token

创建一个 SPL Token 和账户对应的 token account,然后铸造并查询余额。

const web3 = require("@solana/web3.js");
const splToken = require("@solana/spl-token");
const fs = require("fs");

const connection = new web3.Connection(
    web3.clusterApiUrl("devnet"),
    "confirmed"
);

function loadWalletKey(filename) {
    const secretKey = JSON.parse(fs.readFileSync(filename).toString());
    return web3.Keypair.fromSecretKey(new Uint8Array(secretKey));
}

async function main() {
    console.log("🔹 加载本地钱包...");
    const keypair = loadWalletKey("id.json");
    const payer = keypair;
    const mintAuthority = keypair;
    const freezeAuthority = keypair;

    console.log("✅ 钱包已加载:", payer.publicKey.toBase58());

    console.log("\n🔹 正在创建 SPL Token...");
    const tokenMint = await splToken.createMint(
        connection,
        payer,
        mintAuthority.publicKey,
        freezeAuthority.publicKey,
        9
    );
    console.log("创建新SPLToken", tokenMint.toBase58());

    console.log("\n🔹 创建 Token Account...");
    const payerTokenAccount = await splToken.createAssociatedTokenAccount(
        connection,
        payer,
        tokenMint,
        keypair.publicKey
    );

    console.log("✅ Token 账户:", payerTokenAccount.toBase58());

    const mintAmount = 100 * 1e9; // 100 枚代币(9 位小数)
    console.log("\n🔹 铸造代币...");
    await splToken.mintTo(
        connection,
        payer,
        tokenMint,
        payerTokenAccount,
        mintAuthority,
        mintAmount
    );
    console.log(`✅ 成功铸造 ${mintAmount / 1e9} 个代币`);

    console.log("\n🔹 查询 Token 账户余额...");
    const payerTokenAccountInfo = await splToken.getAccount(
        connection,
        payerTokenAccount
    );
    console.log(`✅ Token 余额: ${Number(payerTokenAccountInfo.amount) / 1e9}`);
}

main().catch(console.error);

SPL Token 转账

用创建好的 Token 给一个地址转账,转账前需要获取或者创建接收者的 token account。

const web3 = require("@solana/web3.js");
const splToken = require("@solana/spl-token");
const fs = require("fs");

const connection = new web3.Connection(
    web3.clusterApiUrl("devnet"),
    "confirmed"
);

function loadWalletKey(filename) {
    const secretKey = JSON.parse(fs.readFileSync(filename, "utf8"));
    return web3.Keypair.fromSecretKey(new Uint8Array(secretKey));
}

async function main() {
    console.log("🔹 加载钱包...");
    const from = loadWalletKey("id.json");
    console.log("✅ 发送者地址:", from.publicKey.toBase58());

    const to = new web3.PublicKey("2asHPY75gaEjvXXBDaVKkZQvA44zdhNdBeuBYCtoq5Rj");
    const tokenMint = new web3.PublicKey("3rQBaAAfLxUXddEhqa1dj2gKS53ZdcNKcwYP3Qz3gs7D");

    console.log("🔹 获取或创建发送者的 Token 账户...");
    const fromTokenAccount = await splToken.getOrCreateAssociatedTokenAccount(
        connection,
        from,
        tokenMint,
        from.publicKey
    );
    console.log("✅ 发送者 Token 账户:", fromTokenAccount.address.toBase58());

    console.log("🔹 获取或创建接收者的 Token 账户...");
    const toTokenAccount = await splToken.getOrCreateAssociatedTokenAccount(
        connection,
        from,
        tokenMint,
        to
    );
    console.log("✅ 接收者 Token 账户:", toTokenAccount.address.toBase58());

    const amount = 1 * 1e9; // 1 代币(假设有 9 位小数)

    console.log("🔹 构建转账交易...");
    let transferInstruction = splToken.createTransferInstruction(
        fromTokenAccount.address, // 发送者的 token 账户
        toTokenAccount.address,   // 接收者的 token 账户
        from.publicKey,           // 发送者的公钥
        amount,                   // 发送数量
        [],
        splToken.TOKEN_PROGRAM_ID
    );

    let transaction = new web3.Transaction().add(transferInstruction);

    console.log("🔹 发送交易...");
    let signature = await web3.sendAndConfirmTransaction(connection, transaction, [from]);
    console.log("✅ 交易成功,签名:", signature);

}

main().catch(console.error);

监听账户的 SPL Token 的余额变化

运行此脚本后,可以使用上节转 token 的脚本进行测试。

const web3 = require("@solana/web3.js");
const splToken = require("@solana/spl-token");

const connection = new web3.Connection(
    web3.clusterApiUrl("devnet"),
    "confirmed"
);

// 获取 Token 账户地址
async function getTokenAccount(connection, owner, mint) {
    console.log("🔹 正在查询 Token 账户...");
    const accounts = await connection.getParsedTokenAccountsByOwner(owner, { mint: mint });

    if (accounts.value.length > 0) {
        console.log("✅ 找到 Token 账户:", accounts.value[0].pubkey.toBase58());
        return accounts.value[0].pubkey;
    } else {
        console.log("⚠️ 未找到 Token 账户");
        return null;
    }
}

async function main() {
    console.log("🔹 监听 Token 账户余额变化...");

    // 账户公钥和 Token Mint 地址
    const account = new web3.PublicKey("2asHPY75gaEjvXXBDaVKkZQvA44zdhNdBeuBYCtoq5Rj");
    const tokenMint = new web3.PublicKey("3rQBaAAfLxUXddEhqa1dj2gKS53ZdcNKcwYP3Qz3gs7D");

    // 查询 Token 账户
    const tokenAccount = await getTokenAccount(connection, account, tokenMint);

    if (!tokenAccount) {
        console.error("❌ 监听失败: 该账户没有关联的 Token 账户");
        return;
    }

    console.log("🔹 开始监听账户:", tokenAccount.toBase58());

    // 先获取当前的 Token 余额
    let lastBalance = 0;
    const accountInfo = await connection.getAccountInfo(tokenAccount);
    if (accountInfo && accountInfo.data) {
        const decodedData = splToken.AccountLayout.decode(accountInfo.data);
        lastBalance = Number(decodedData.amount) / 1e9; // 转换为 9 位精度
        console.log(`🔹 初始 Token 余额: ${lastBalance} 个(精度 9 位)`);
    }

    // 监听 Token 账户余额变化
    connection.onAccountChange(tokenAccount, async (accountInfo) => {
        // 获取 SPL Token 账户数据并解码
        const parsedData = accountInfo.data;
        if (parsedData && parsedData.length > 0) {
            // 使用 spl-token 的 AccountLayout 解码数据
            const decodedData = splToken.AccountLayout.decode(parsedData);

            const tokenBalance = Number(decodedData.amount) / 1e9; // 转换为 9 位精度

            // 打印余额变化
            if (lastBalance !== 0) {
                const changeInBalance = tokenBalance - lastBalance;
                console.log(`🔄 Token 余额变化: ${changeInBalance} 个(精度 9 位)`);
            }

            // 更新上一次的余额
            lastBalance = tokenBalance;
        } else {
            console.log("⚠️ 无法解析 Token 账户数据");
        }
    });

}

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

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,做过FHE,联盟链,现在是智能合约开发者。 刨根问底探链上真相,品味坎坷悟Web3人生。