Documentation Index
Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
Use this file to discover all available pages before exploring further.
包含以下内容的配置对象:Commitment 级别(processed、confirmed、finalized)
账户数据的编码格式(base58、base64、jsonParsed)
代码示例
基本请求
curl https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getTokenAccountsByDelegate",
"params": [
"4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj",
{
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
]
}'
使用 web3.js
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY');
// Get token accounts by delegate
const delegate = new PublicKey('4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj');
const programId = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
const accounts = await connection.getTokenAccountsByDelegate(delegate, { programId });
console.log('Token accounts:', accounts);
// Get token accounts by delegate with analysis
async function getTokenAccountsByDelegateWithAnalysis(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
) {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
return {
accounts,
analysis: {
totalAccounts: accounts.value.length,
totalBalance: accounts.value.reduce((sum, acc) => {
const amount = BigInt(acc.account.data.parsed.info.tokenAmount.amount);
return sum + amount;
}, BigInt(0)),
byMint: accounts.value.reduce((acc, account) => {
const mint = account.account.data.parsed.info.mint;
const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
acc[mint] = (acc[mint] || BigInt(0)) + amount;
return acc;
}, {} as Record<string, bigint>),
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
}
};
}
注意事项
- 返回给定公钥作为代理人的所有代币账户
- 代理人有权从这些账户转移代币
- 响应是即时的,因为它从当前状态读取
- 账户可能随代币转账和其他操作而变化
- 代理人必须是有效的公钥
最佳实践
- 根据需求使用适当的 commitment 级别
- 在适当时缓存结果以减少 RPC 负载
- 监控代理账户的变化
- 考虑使用 WebSocket 订阅获取实时更新
- 适当处理网络错误并重试
常见错误
| 错误码 | 消息 | 解决方案 |
|---|
| -32601 | Method not found | 验证是否连接到 Solana RPC 节点 |
| -32602 | Invalid params | 检查代理人公钥和配置 |
| -32007 | Delegate not found | 验证代理人是否存在 |
| -32008 | Invalid program ID | 验证程序 ID 是否正确 |
-
代理账户分析
interface DelegateAccountAnalysis {
delegate: string;
accounts: Array<{
pubkey: string;
mint: string;
balance: string;
owner: string;
}>;
metrics: {
totalAccounts: number;
totalBalance: string;
byMint: Record<string, string>;
byOwner: Record<string, number>;
};
metadata: {
timestamp: number;
commitment?: string;
};
}
class DelegateAccountAnalyzer {
async analyzeDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountAnalysis> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
const byMint: Record<string, bigint> = {};
const byOwner: Record<string, number> = {};
let totalBalance = BigInt(0);
accounts.value.forEach(account => {
const mint = account.account.data.parsed.info.mint;
const owner = account.account.data.parsed.info.owner;
const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
byMint[mint] = (byMint[mint] || BigInt(0)) + amount;
byOwner[owner] = (byOwner[owner] || 0) + 1;
totalBalance += amount;
});
return {
delegate: delegate.toBase58(),
accounts: accounts.value.map(account => ({
pubkey: account.pubkey,
mint: account.account.data.parsed.info.mint,
balance: account.account.data.parsed.info.tokenAmount.amount,
owner: account.account.data.parsed.info.owner
})),
metrics: {
totalAccounts: accounts.value.length,
totalBalance: totalBalance.toString(),
byMint: Object.fromEntries(
Object.entries(byMint).map(([mint, amount]) => [mint, amount.toString()])
),
byOwner
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
};
}
}
-
代理账户监控
interface DelegateAccountChange {
delegate: string;
changes: Array<{
type: 'added' | 'removed' | 'modified';
account: string;
previousBalance?: string;
currentBalance?: string;
}>;
metadata: {
timestamp: number;
};
}
class DelegateAccountMonitor {
private previousAccounts: Map<string, string> = new Map();
async monitorDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountChange | null> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
const currentAccounts = new Map(
accounts.value.map(account => [
account.pubkey,
account.account.data.parsed.info.tokenAmount.amount
])
);
const changes: Array<{
type: 'added' | 'removed' | 'modified';
account: string;
previousBalance?: string;
currentBalance?: string;
}> = [];
this.previousAccounts.forEach((balance, account) => {
if (!currentAccounts.has(account)) {
changes.push({
type: 'removed',
account,
previousBalance: balance
});
} else if (currentAccounts.get(account) !== balance) {
changes.push({
type: 'modified',
account,
previousBalance: balance,
currentBalance: currentAccounts.get(account)
});
}
});
currentAccounts.forEach((balance, account) => {
if (!this.previousAccounts.has(account)) {
changes.push({
type: 'added',
account,
currentBalance: balance
});
}
});
this.previousAccounts = currentAccounts;
if (changes.length > 0) {
return {
delegate: delegate.toBase58(),
changes,
metadata: {
timestamp: Date.now()
}
};
}
return null;
}
}
-
代理账户规划
interface DelegateAccountPlan {
delegate: string;
currentAccounts: Array<{
pubkey: string;
mint: string;
balance: string;
}>;
recommendations: Array<{
type: 'consolidate' | 'diversify' | 'rebalance';
accounts: string[];
reason: string;
}>;
metadata: {
timestamp: number;
};
}
class DelegateAccountPlanner {
private readonly minBalancePerAccount = BigInt(1000000); // 1 token
private readonly maxAccountsPerMint = 5;
async planDelegateAccounts(
delegate: PublicKey,
config: { programId: PublicKey; commitment?: string }
): Promise<DelegateAccountPlan> {
const accounts = await connection.getTokenAccountsByDelegate(delegate, config);
const byMint = accounts.value.reduce((acc, account) => {
const mint = account.account.data.parsed.info.mint;
if (!acc[mint]) {
acc[mint] = [];
}
acc[mint].push(account);
return acc;
}, {} as Record<string, typeof accounts.value>);
const recommendations: Array<{
type: 'consolidate' | 'diversify' | 'rebalance';
accounts: string[];
reason: string;
}> = [];
Object.entries(byMint).forEach(([mint, mintAccounts]) => {
const lowBalanceAccounts = mintAccounts.filter(account =>
BigInt(account.account.data.parsed.info.tokenAmount.amount) < this.minBalancePerAccount
);
if (lowBalanceAccounts.length > 0) {
recommendations.push({
type: 'consolidate',
accounts: lowBalanceAccounts.map(account => account.pubkey),
reason: `Accounts with balances below minimum threshold for mint ${mint}`
});
}
if (mintAccounts.length > this.maxAccountsPerMint) {
recommendations.push({
type: 'consolidate',
accounts: mintAccounts.map(account => account.pubkey),
reason: `Too many accounts (${mintAccounts.length}) for mint ${mint}`
});
}
});
return {
delegate: delegate.toBase58(),
currentAccounts: accounts.value.map(account => ({
pubkey: account.pubkey,
mint: account.account.data.parsed.info.mint,
balance: account.account.data.parsed.info.tokenAmount.amount
})),
recommendations,
metadata: {
timestamp: Date.now()
}
};
}
}