目录
[1.Solana 核心概念简述](#1.Solana 核心概念简述)
[1.1. 账户(Account)](#1.1. 账户(Account))
[1.2. 交易(Transaction)](#1.2. 交易(Transaction))
[1.3. 交易指令(Instruction)](#1.3. 交易指令(Instruction))
[1.4. SPL 代币](#1.4. SPL 代币)
[1.5. 合约(Program)](#1.5. 合约(Program))
[1.6. 租约(Rent)](#1.6. 租约(Rent))
[2.3.Token 账户查询](#2.3.Token 账户查询)
[2.4.创建 Token 账户](#2.4.创建 Token 账户)
[4.通过 WalletAdatper 与钱包交互](#4.通过 WalletAdatper 与钱包交互)
[4.1 依赖和示例界面](#4.1 依赖和示例界面)
[4.2Solana 钱包 API 整理](#4.2Solana 钱包 API 整理)
[4.2.2SolongWallet 适配器集成](#4.2.2SolongWallet 适配器集成)
[4.2.4 交易操作](#4.2.4 交易操作)
[4.2.5 RPC 配置和管理](#4.2.5 RPC 配置和管理)
1.Solana 核心概念简述
Solana 是一个高性能的区块链平台,其核心概念包括 账户(Account) 、交易(Transaction) 、合约(Program) 和 租约(Rent)。以下是对这些概念的简短易懂概括:
1.1. 账户(Account)
-
"一切皆账户":类似 Linux 系统把所有资源抽象为"文件",Solana 中所有的信息(如代币余额、合约代码等)都存储在账户对象中。
-
账户结构 :
- lamports:账户余额(Solana 的原生代币单位)。
- data:存储的数据(对于合约账户,这里是代码;对于用户账户,这里可能是代币信息)。
- owner:账户的所有者(通常是一个合约地址,决定谁能操作这个账户)。
- executable:是否为可执行合约(如果是合约账户,此值为 true)。
- rent_epoch:下次需要支付租金的周期。
-
账户与签名 :
1.2. 交易(Transaction)
- 用户账户本质是一个 私钥,通过 Ed25519 算法生成(高效、安全、签名短)。
- 账户地址是私钥对应的 公钥,经过 Base58 编码后变成可读形式(如 HawRVHh7t4d3H3bitWHFt25WhhoDmbJMCfWdESQQoYEy)。
- 私钥签名用于证明对账户的控制权。
-
定义:交易是用户与区块链交互的方式,例如转账或调用合约。
-
组成 :
- 一系列 交易指令(Instruction):指定要执行的操作、涉及的账户和数据。
- 签名:由发起者的私钥生成,用于验证交易有效性。
- 账户列表:交易中涉及的所有账户地址。
- 最近区块哈希:确保交易的时效性。
1.3. 交易指令(Instruction)
- 定义:交易的核心单元,描述具体的操作。
- 结构 :
- program_id_index:要调用的合约地址(在账户列表中的索引)。
- accounts:操作涉及的账户。
- data:输入的具体数据。
1.4. SPL 代币(SPL)
在以太坊中,普通代币被一个叫ERC20的提案定了规范,可以认为普通代币合约统一叫做ERC20代币。
那么Solana世界里的ERC20代币是什么呢?答案就是SPL代币。
The Solana Program Library (SPL) is a collection of on-chain programs targeting the Sealevel parallel runtime.
SPL Token是 " Solana Program Library"中的一个组成部分,叫做"Token Program",简称为SPL Token。
所有的代币都有这个合约来管理,该合约代码在 https://github.com/solana-labs/solana-program-library/tree/master/token
不同于以太坊中,一个代币就是一个合约。
SPL Token中,一个代币,仅仅是一个归Token合约管理的普通的Account对象,这个对象里面的二进制数据定义了 这个代币的基本属性
1.5. 合约(Program)
- 类型 :
- 系统合约(Native Program):由 Solana 官方提供,如 System Program(创建账户、转账)、BPF Loader Program(部署合约)。
- 普通合约(On Chain Program):用户开发并部署的合约,如代币相关合约。
- 特点 :
- 合约是存储在账户中的可执行代码(executable = true)。
- 用户通过交易调用合约执行逻辑。
- Solana 的合约可以更新或销毁,销毁时存储资源会退还给部署者。
1.6. 租约(Rent)
- 什么是租约 :
- 账户需要支付"租金"来保持数据存储在区块链上,租金根据存储的数据量和时间计算。
- 规则 :
- 免租:账户余额超过"两年租金"的阈值则无需支付租金。
- 租金不足:余额低于免租阈值或付不出租金的账户会被"垃圾收集"(删除)。
- 与交易费用的区别 :
- 租金是为存储付费。
- 交易费用是为处理指令付费。
2通过RPC与Solana交互
2.1.配置环境
首先,将钱包配置指向 Devnet 环境:
bash
solana config set --url https://api.devnet.solana.com
2.2.查看钱包信息
查看当前钱包地址:
bash
solana address
获取测试网 SOL(开发资金):
bash
solana airdrop 2
查看钱包 SOL 余额:
bash
solana balance
查看钱包中所有 SPL Token 余额:
bash
spl-token accounts
2.3.Token 账户查询
通过这个 curl
请求,你可以查询 Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi
这个钱包地址下,所有与 7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9
这个 SPL Token(Token 的 Mint 地址)相关的 Token 账户。
bash
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '
{
"jsonrpc": "2.0",
"id": 1,
"method": "getTokenAccountsByOwner",
"params": [
"Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi",
{
"mint": "7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9"
},
{
"encoding": "jsonParsed"
}
]
}
'
查询结果解析:
bash
{
"jsonrpc": "2.0",
"result": {
"context": {
"apiVersion": "2.1.13",
"slot": 363620820
},
"value": [
{
"account": {
"data": {
"parsed": {
"info": {
"isNative": false,
"mint": "7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9",
"owner": "Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi",
"state": "initialized",
"tokenAmount": {
"amount": "94000000000",
"decimals": 9,
"uiAmount": 94,
"uiAmountString": "94"
}
},
"type": "account"
},
"program": "spl-token",
"space": 165
},
"executable": false,
"lamports": 315139280,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"rentEpoch": 18446744073709552000,
"space": 165
},
"pubkey": "EZhhUANUMKsRhRMArczio1kLc9axefTUAh5xofGX35AK"
}
]
},
"id": 1
}
pubkey
:EZhhUANUMKsRhRMArczio1kLc9axefTUAh5xofGX35AK
- Token 账户公钥mint
:7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9
- SPL Token 的类型标识符owner
:Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi
- 该 Token 账户的拥有者钱包地址tokenAmount
:当前持有的代币数量(带有小数位信息)
2.4.创建 Token 账户
为某个 SPL Token 创建关联账户(需要确保接收者有对应的 Token 账户才能接收特定代币):
bash
spl-token create-account 9pbWQJHTSLELGekc85QHYCHozRdLo4si2nCPbMNZ2bxj --owner HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm --fee-payer /Users/linzhihao/.config/solana/id.json
2.5.实时监控账户变动
使用 WebSocket 订阅账户变化(需要提前安装 wscat 工具):
bash
wscat -c wss://api.devnet.solana.com
连接后发送订阅请求:
bash
{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm",{"encoding":"jsonParsed","commitment":"finalized"}]}
监听Solana token account HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm
2.6.转账操作
转移 SPL Token 到另一个钱包(自动为对方创建接收账户):
bash
spl-token transfer --fund-recipient 9pbWQJHTSLELGekc85QHYCHozRdLo4si2nCPbMNZ2bxj 0.01 BBy1K96Y3bohNeiZTHuQyB53LcfZv6NWCSWqQp89TiVu
--fund-recipient
:如果目标地址没有该Token的账户,则为其创建一个。1
:转账的Token数量,1表示转1个单位的该Token。BBy1K96Y3bohNeiZTHuQyB53LcfZv6NWCSWqQp89TiVu
:目标收件人的Solana Public Address
3.Solana的Web3.js
3.1.交易代码
javascript
// solana-test.js
const { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction } = require('@solana/web3.js');
const fs = require('fs');
const bs58 = require('bs58');
async function main() {
try {
// 1. 读取 id.json 文件
const idJson = JSON.parse(fs.readFileSync('/Users/linzhihao/.config/solana/id.json', 'utf8'));
// 2. 解码为 Uint8Array
const secretKey = new Uint8Array(idJson);
// 3. 创建 Keypair
const keypair = Keypair.fromSecretKey(secretKey);
console.log('✅ Loaded keypair from secret key');
console.log(` Address: ${keypair.publicKey.toString()}`);
// 4. 连接到 Solana 网络
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
// 5. Check account balance
const balance = await connection.getBalance(keypair.publicKey);
console.log(`✅ Current balance: ${balance / LAMPORTS_PER_SOL} SOL`);
// If balance is too low, request an airdrop
if (balance < 0.1 * LAMPORTS_PER_SOL) {
console.log('⏳ Requesting airdrop of 1 SOL...');
const airdropSignature = await connection.requestAirdrop(
keypair.publicKey,
1 * LAMPORTS_PER_SOL
);
// Wait for confirmation
const latestBlockhash = await connection.getLatestBlockhash('finalized');
await connection.confirmTransaction({
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
signature: airdropSignature
});
const newBalance = await connection.getBalance(keypair.publicKey);
console.log(`✅ New balance after airdrop: ${newBalance / LAMPORTS_PER_SOL} SOL`);
}
// 6. Set up recipient address for transfer (just an example address)
const recipientAddress = new PublicKey('Ey9M2QMRfg8Tuysyh3UEdeB9NwZmRaJU5FUjKtBSNJnb');
const transferAmount = 0.01 * LAMPORTS_PER_SOL; // 0.01 SOL
console.log(`⏳ Preparing to send ${transferAmount / LAMPORTS_PER_SOL} SOL to ${recipientAddress.toString()}...`);
// 7. Get latest blockhash
const latestBlockhash = await connection.getLatestBlockhash('finalized');
console.log(`✅ Fetched latest blockhash. Last Valid Height: ${latestBlockhash.lastValidBlockHeight}`);
// 8. Create a transfer instruction
const transferInstruction = SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: recipientAddress,
lamports: transferAmount
});
// 9. Create a transaction message
const message = new TransactionMessage({
payerKey: keypair.publicKey,
recentBlockhash: latestBlockhash.blockhash,
instructions: [transferInstruction]
}).compileToV0Message();
// 10. Create a versioned transaction
const transaction = new VersionedTransaction(message);
// 11. Sign the transaction
transaction.sign([keypair]);
console.log('✅ Transaction signed');
// 12. Send the transaction
const signature = await connection.sendTransaction(transaction);
console.log(`✅ Transaction sent with signature: ${signature}`);
// 13. Confirm the transaction
console.log('⏳ Confirming transaction...');
await connection.confirmTransaction({
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
signature: signature
});
console.log('✅ Transaction confirmed');
// 14. Check the new balance
const newBalance = await connection.getBalance(keypair.publicKey);
console.log(`✅ New balance after transfer: ${newBalance / LAMPORTS_PER_SOL} SOL`);
} catch (error) {
console.error('❌ Error:', error);
}
}
main();
3.2.输出结果
✅ Loaded keypair from secret key
Address: Ed5NC8cwDiJ7A8831DoAdELq6aouydCbywUDLg3EwC8k
✅ Current balance: 2.89027628 SOL
⏳ Preparing to send 0.01 SOL to Ey9M2QMRfg8Tuysyh3UEdeB9NwZmRaJU5FUjKtBSNJnb...
✅ Fetched latest blockhash. Last Valid Height: 351840779
✅ Transaction signed
✅ Transaction sent with signature: 2x4DEvKHvuXDtrFUfPhLL1EcicYTf1AKKuuer6gU5o2Rrt14sa85uRGgrApZJUPLJod6JdgGuezwVBbb5x3RLs7n
⏳ Confirming transaction...
✅ Transaction confirmed
✅ New balance after transfer: 2.88027128 SOL
4.通过 WalletAdatper 与钱包交互
4.1 依赖和示例界面
javascript
npm install \
@solana/wallet-adapter-react@0.15.35 \
@solana/wallet-adapter-base@0.9.23 \
@solana/wallet-adapter-wallets@0.17.0 \
npm install @solana/buffer-layout
npm install @solana/web3.js@latest
npm install @craco/craco --save-dev
npm install web-vitals
安转chrom插件Phantom

4.2Solana 钱包 API 整理
4.2.1关键包和导入
javascript
// 核心适配器和连接
import { ConnectionProvider, WalletProvider, useConnection, useWallet } from '@solana/wallet-adapter-react';
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
// UI 组件
import { WalletDisconnectButton, WalletMultiButton } from '@solana/wallet-adapter-react-ui';
// 特定钱包适配器
import { SolongWalletAdapter } from '@solana/wallet-adapter-solong';
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom';
// Solana Web3 工具
import { Keypair, Connection, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction } from '@solana/web3.js';
4.2.2SolongWallet 适配器集成
javascript
// 初始化 SolongWallet 适配器
const solongAdapter = new SolongWalletAdapter();
// 组合多个钱包适配器
const wallets = useMemo(
() => [
new PhantomWalletAdapter(),
new SolongWalletAdapter(),
// 可以添加更多适配器...
],
[]
);
// 提供钱包适配器给应用
<WalletProvider wallets={wallets} autoConnect>
{/* 应用组件 */}
</WalletProvider>
4.2.3钱包连接和状态管理
javascript
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{/* 应用组件 */}
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
<div style={styles.walletButtons}>
<WalletMultiButton />
<WalletDisconnectButton />
</div>
4.2.4 交易操作
javascript
// 在组件内部获取钱包连接和功能
const { connection } = useConnection();
const { publicKey, sendTransaction } = useWallet();
// 创建交易
const transaction = new Transaction();
const recipientPubKey = Keypair.generate().publicKey;
// 添加转账指令
transaction.add(
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: recipientPubKey,
lamports: 0.01 * LAMPORTS_PER_SOL,
})
);
// 获取最新区块哈希
const { blockhash, lastValidBlockHeight } = value;
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
// 发送交易
const signature = await sendTransaction(transaction, connection, {
minContextSlot,
skipPreflight: false
});
// 等待确认
const confirmationResponse = await connection.confirmTransaction({
blockhash,
lastValidBlockHeight,
signature,
}, 'confirmed');
4.2.5 RPC 配置和管理
javascript
export const RPC_CONFIG = {
// 默认 Solana Devnet - 有低速率限制
DEFAULT: clusterApiUrl(WalletAdapterNetwork.Devnet),
// 替代端点 - 在这里添加您的 API 密钥
HELIUS: 'https://rpc-devnet.helius.xyz/your-api-key',
QUICKNODE: 'https://your-quicknode-devnet-endpoint',
ALCHEMY: 'https://solana-devnet.g.alchemy.com/v2/your-api-key',
// 默认使用哪个端点
ACTIVE: 'DEFAULT',
// 速率限制错误的最大重试次数
MAX_RETRIES: 3,
// 指数退避的基本延迟(毫秒)
BASE_DELAY: 1000,
// 余额轮询间隔(毫秒)- 增加到 30 秒
POLLING_INTERVAL: 30000,
};