概述
Helius Sender 是一种专门用于超低延迟交易提交的服务。它通过同时发送到 Solana 验证者和 Jito 来优化交易延迟,为您的交易提供多种被包含在区块中的路径。双重路由
同时发送到验证器和Jito以获得最佳速度
全球端点
HTTPS端点自动路由到最近的位置用于前端,区域HTTP用于后端
无积分
所有计划均可使用且不消耗API积分
高吞吐量
默认15 TPS,可根据需要请求更高限制
快速入门指南
准备好提交您的第一个超低延迟 Solana 交易了吗?本指南将帮助您在几分钟内开始使用 Helius Sender。最棒的是:您不需要任何付费计划或特殊访问权限 - Sender 对所有用户开放,并且不消耗 API 积分。1
创建您的免费 Helius 账户
首先在 Helius Dashboard 创建您的免费账户。Sender 在所有计划中都可用,包括免费层,并且不消耗任何 API 积分。
2
获取您的 API 密钥
导航到 API Keys 部分并复制您的密钥。您将使用此密钥获取区块哈希和交易确认,而 Sender 负责交易提交。
3
发送您的第一笔交易
让我们使用 Sender 发送一个简单的 SOL 转账。此示例包括所有必需的组件:小费、优先费用和跳过预检。
- @solana/web3.js
- @solana/kit
报告错误代码
复制
询问AI
import {
Connection,
TransactionMessage,
VersionedTransaction,
SystemProgram,
PublicKey,
Keypair,
LAMPORTS_PER_SOL,
ComputeBudgetProgram
} from '@solana/web3.js';
import bs58 from 'bs58';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta"
// ... more tip accounts available
];
async function sendWithSender(
keypair: Keypair,
recipientAddress: string
): Promise<string> {
const connection = new Connection(
'https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY'
);
const { value: { blockhash } } = await connection.getLatestBlockhashAndContext('confirmed');
// Build transaction with tip transfer and transfer to recipient
const transaction = new VersionedTransaction(
new TransactionMessage({
instructions: [
ComputeBudgetProgram.setComputeUnitLimit({ units: 100_000 }),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 200_000 }),
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: new PublicKey(recipientAddress),
lamports: 0.001 * LAMPORTS_PER_SOL,
}),
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
lamports: 0.0002 * LAMPORTS_PER_SOL,
})
],
payerKey: keypair.publicKey,
recentBlockhash: blockhash,
}).compileToV0Message()
);
transaction.sign([keypair]);
console.log('Sending transaction via Sender endpoint...');
const response = await fetch('https://sender.helius-rpc.com/fast', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now().toString(),
method: 'sendTransaction',
params: [
Buffer.from(transaction.serialize()).toString('base64'),
{
encoding: 'base64',
skipPreflight: true, // Required for Sender
maxRetries: 0
}
]
})
});
const json = await response.json();
if (json.error) {
throw new Error(json.error.message);
}
console.log('Transaction sent:', json.result);
return json.result;
}
// Usage
const keypair = Keypair.fromSecretKey(bs58.decode('YOUR_PRIVATE_KEY'));
sendWithSender(keypair, 'RECIPIENT_ADDRESS');
报告错误代码
复制
询问AI
import { pipe } from "@solana/kit";
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
lamports,
getBase64EncodedWireTransaction,
createKeyPairSignerFromBytes,
address,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
import bs58 from 'bs58';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta"
// ... more tip accounts available
];
async function sendWithSender(
privateKeyB58: string,
recipientAddress: string
): Promise<string> {
// Load signer from base58 private key
const ownerSigner = await createKeyPairSignerFromBytes(bs58.decode(privateKeyB58));
// Init RPC and fetch blockhash
const rpc = createSolanaRpc('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY');
const { value: blockhash } = await rpc.getLatestBlockhash().send();
// Build + sign transaction
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: 100_000 }), m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitPriceInstruction({ microLamports: 200_000 }), m),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(recipientAddress),
amount: lamports(1_000_000n), // 0.001 SOL
}),
m
),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
amount: lamports(200_000n), // 0.0002 SOL
}),
m
)
);
const signedTx = await signTransactionMessageWithSigners(tx);
const base64Tx = getBase64EncodedWireTransaction(signedTx);
console.log('Sending transaction via Sender endpoint...');
// Send via Sender
const res = await fetch("https://sender.helius-rpc.com/fast", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [
base64Tx,
{ encoding: "base64", skipPreflight: true, maxRetries: 0 },
],
}),
});
const { result: sig, error } = await res.json();
if (error) throw new Error(error.message);
console.log("Transaction sent: ", sig);
return sig;
}
// Usage
sendWithSender('YOUR_PRIVATE_KEY', 'RECIPIENT_ADDRESS');
4
成功!了解发生了什么
你已通过 Sender 成功提交了一笔交易!以下是其成功的原因:
- 无消耗积分:Sender 对所有用户免费
- 双重路由:你的交易同时发送给验证者和 Jito
- 必要的小费:0.0002 SOL 的小费使 Jito 能参与拍卖
- 优先费用:向验证者表明你愿意支付以获得优先处理
- 跳过预检:优化速度而非验证
路由选项
默认双重路由
同时将交易发送到 Solana 验证者和 Jito 基础设施,以最大化包含概率。需要至少 0.0002 SOL 的小费。
仅 SWQOS 替代方案
对于成本优化的交易,在任何端点 URL 中添加
?swqos_only=true。仅通过 SWQOS 基础设施路由,最低小费要求为 0.000005 SOL。要求
强制要求:所有交易必须包含小费(最低 0.0002 SOL,或仅 SWQOS 为 0.000005 SOL)、优先费用,并跳过预检检查。
1. 跳过预检(强制)
skipPreflight 参数必须设置为 true。Sender针对优先考虑速度而非交易验证的交易者进行了优化。
报告错误代码
复制
询问AI
{
"skipPreflight": true // Required: must be true
}
由于跳过了预检检查,请确保您的交易在提交前已正确构建和资助。无效交易将在提交后被网络拒绝。
2. 必须包含小费和优先费用
通过Sender提交的所有交易必须同时包含小费和优先费用:- 小费:最低 0.0002 SOL 转账到指定的小费账户(或仅 SWQOS 为 0.000005 SOL)
指定小费账户(mainnet-beta)
指定小费账户(mainnet-beta)
报告错误代码
复制
询问AI
4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE
D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ
9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta
5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn
2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD
2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ
wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF
3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT
4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey
4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or
- 优先费用:通过
ComputeBudgetProgram.setComputeUnitPrice计算单元定价,以在验证者队列中优先处理您的交易
为什么两者都需要
- 小费:启用对Jito基础设施和基于拍卖的交易包含的访问
- 优先费用:通过Solana的本地优先系统向验证者表明您愿意支付优先处理费用
- 双重收益:小费让您可以访问Jito的拍卖,而优先费用提高了您的交易在验证者中的优先级——两者结合最大化包含概率
小费和优先费用指南
Jito 小费:参与拍卖的最低要求是 0.0002 SOL。有关当前最佳实践小费大小,请参阅 Jito 小费指南。 优先费用:使用Helius优先费用API获取实时费用建议。端点
Sender端点根据您的使用情况提供多种配置:- 前端/浏览器应用程序
- Backend/Server Applications
- Connection Warming
推荐用于前端应用程序以避免CORS问题:
报告错误代码
复制
询问AI
https://sender.helius-rpc.com/fast # Global HTTPS endpoint
HTTPS 端点解决了使用区域 HTTP 端点时,基于浏览器的应用程序出现的 CORS 预检失败问题。此端点会自动路由到最近的位置以获得最佳性能。将其用于所有前端/浏览器实现。
区域 HTTP 端点以获得最佳服务器到服务器的延迟:
报告错误代码
复制
询问AI
http://slc-sender.helius-rpc.com/fast # Salt Lake City
http://ewr-sender.helius-rpc.com/fast # Newark
http://lon-sender.helius-rpc.com/fast # London
http://fra-sender.helius-rpc.com/fast # Frankfurt
http://ams-sender.helius-rpc.com/fast # Amsterdam
http://sg-sender.helius-rpc.com/fast # Singapore
http://tyo-sender.helius-rpc.com/fast # Tokyo
对于后端/服务器应用程序,请选择离您的基础设施最近的区域 HTTP 端点以获得最佳性能。
HTTPS(前端):HTTP(后端):
报告错误代码
复制
询问AI
https://sender.helius-rpc.com/ping # Global HTTPS ping (auto-routes to nearest location)
报告错误代码
复制
询问AI
http://slc-sender.helius-rpc.com/ping # Salt Lake City
http://ewr-sender.helius-rpc.com/ping # Newark
http://lon-sender.helius-rpc.com/ping # London
http://fra-sender.helius-rpc.com/ping # Frankfurt
http://ams-sender.helius-rpc.com/ping # Amsterdam
http://sg-sender.helius-rpc.com/ping # Singapore
http://tyo-sender.helius-rpc.com/ping # Tokyo
连接预热
对于提交事务之间间隔时间较长的应用程序,使用 ping 端点来保持连接的温暖并减少冷启动延迟。Ping 端点使用
ping 端点接受简单的 GET 请求并返回基本响应以保持连接活跃:报告错误代码
复制
询问AI
# Frontend applications - use HTTPS (auto-routes to nearest location)
curl https://sender.helius-rpc.com/ping
# Backend applications - use regional HTTP
curl http://slc-sender.helius-rpc.com/ping
报告错误代码
复制
询问AI
// Keep connection warm during idle periods
async function warmConnection(endpoint: string) {
try {
const response = await fetch(`${endpoint}/ping`);
console.log('Connection warmed:', response.ok);
} catch (error) {
console.warn('Failed to warm connection:', error);
}
}
// Frontend applications - use HTTPS endpoint
setInterval(() => {
warmConnection('https://sender.helius-rpc.com');
}, 30000);
// Backend/server applications - use regional HTTP endpoint
setInterval(() => {
warmConnection('http://slc-sender.helius-rpc.com');
}, 30000);
当您的应用程序在事务之间的间隔时间超过 1 分钟时,使用连接预热以保持最佳提交延迟。
使用
Sender 端点使用与标准 RPC 端点相同的方法,但有特定要求以获得最佳性能。所有事务必须包括小费和优先费用,并跳过预检检查。基本请求格式
报告错误代码
复制
询问AI
{
"id": "unique-request-id",
"jsonrpc": "2.0",
"method": "sendTransaction",
"params": [
"BASE64_ENCODED_TRANSACTION", // Must include both tip and priority fee instructions
{
"encoding": "base64",
"skipPreflight": true, // Required: must be true
"maxRetries": 0
}
]
}
上述内容必须包含一个 SOL 转账指令,最低小费到指定的小费账户和一个计算单元价格指令。没有这两个要求,您的事务将被拒绝。
简单代码示例
- @solana/web3.js
- @solana/kit
报告错误代码
复制
询问AI
import {
Connection,
TransactionMessage,
VersionedTransaction,
SystemProgram,
PublicKey,
Keypair,
LAMPORTS_PER_SOL,
ComputeBudgetProgram
} from '@solana/web3.js';
import bs58 from 'bs58';
const PRIV_B58 = 'Your Private Key';
const RECIPIENT = 'Random Recipient';
const HELIUS_API_KEY = 'Your API Key';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];
async function sendWithSender(
keypair: Keypair,
recipientAddress: string
): Promise<string> {
const connection = new Connection(
`https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`
);
const { value: { blockhash } } = await connection.getLatestBlockhashAndContext('confirmed');
// Build transaction with tip transfer and transfer to recipient
const transaction = new VersionedTransaction(
new TransactionMessage({
instructions: [
ComputeBudgetProgram.setComputeUnitLimit({ units: 100_000 }),
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 200_000 }),
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: new PublicKey(recipientAddress),
lamports: 0.001 * LAMPORTS_PER_SOL,
}),
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
lamports: 0.0002 * LAMPORTS_PER_SOL,
})
],
payerKey: keypair.publicKey,
recentBlockhash: blockhash,
}).compileToV0Message()
);
// Sign transaction
transaction.sign([keypair]);
console.log('Sending transaction via Sender endpoint...');
// Frontend: Use HTTPS endpoint to avoid CORS issues
const SENDER_ENDPOINT = 'https://sender.helius-rpc.com/fast';
// Backend: Use regional HTTP endpoint closest to your servers
// const SENDER_ENDPOINT = 'http://slc-sender.helius-rpc.com/fast';
const response = await fetch(SENDER_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now().toString(),
method: 'sendTransaction',
params: [
Buffer.from(transaction.serialize()).toString('base64'),
{
encoding: 'base64',
skipPreflight: true, // Required for Sender
maxRetries: 0
}
]
})
});
const json = await response.json();
if (json.error) {
throw new Error(json.error.message);
}
const signature = json.result;
console.log('Transaction sent:', signature);
// Confirmation check
for (let i = 0; i < 30; i++) {
const status = await connection.getSignatureStatuses([signature]);
console.log('Status:', status?.value[0]?.confirmationStatus || 'pending');
if (status?.value[0]?.confirmationStatus === "confirmed") {
console.log('Transaction confirmed!');
return signature;
}
await new Promise(resolve => setTimeout(resolve, 500));
}
console.log('Transaction may have succeeded but confirmation timed out');
return signature;
}
// Send transaction
sendWithSender(Keypair.fromSecretKey(bs58.decode(PRIV_B58)), RECIPIENT);
报告错误代码
复制
询问AI
import { pipe } from "@solana/kit";
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
lamports,
getBase64EncodedWireTransaction,
createKeyPairSignerFromBytes,
address,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
import bs58 from 'bs58';
const PRIV_B58 = 'Your Private Key';
const RECIPIENT = 'Random Recipient';
const HELIUS_API_KEY = 'Your API Key';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];
async function sendWithSender(
privateKeyB58: string,
recipientAddress: string
): Promise<string> {
// Load signer from base58 private key
const ownerSigner = await createKeyPairSignerFromBytes(bs58.decode(privateKeyB58));
// Init RPC and fetch blockhash
const rpc = createSolanaRpc(`https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
// Build + sign transaction
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitLimitInstruction({ units: 100_000 }), m),
(m) => appendTransactionMessageInstruction(getSetComputeUnitPriceInstruction({ microLamports: 200_000 }), m),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(recipientAddress),
amount: lamports(1_000_000n), // 0.001 SOL
}),
m
),
(m) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: ownerSigner,
destination: address(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
amount: lamports(200_000n), // 0.0002 SOL
}),
m
)
);
const signedTx = await signTransactionMessageWithSigners(tx);
const base64Tx = getBase64EncodedWireTransaction(signedTx);
console.log('Sending transaction via Sender endpoint...');
// Frontend: Use HTTPS endpoint to avoid CORS issues
const SENDER_ENDPOINT = 'https://sender.helius-rpc.com/fast';
// Backend: Use regional HTTP endpoint closest to your servers
// const SENDER_ENDPOINT = 'http://slc-sender.helius-rpc.com/fast';
// Send via Sender
const res = await fetch(SENDER_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [
base64Tx,
{ encoding: "base64", skipPreflight: true, maxRetries: 0 },
],
}),
});
const { result: signature, error } = await res.json();
if (error) throw new Error(error.message);
console.log("Transaction sent: ", signature);
// Confirmation check
for (let i = 0; i < 30; i++) {
const status = await rpc.getSignatureStatuses([signature]).send();
console.log('Status:', status?.value[0]?.confirmationStatus || 'pending');
if (status?.value[0]?.confirmationStatus === "confirmed") {
console.log('Transaction confirmed!');
return signature;
}
await new Promise(resolve => setTimeout(resolve, 500));
}
console.log('Transaction may have succeeded but confirmation timed out');
return signature;
}
// Send transaction
sendWithSender(PRIV_B58, RECIPIENT);
动态优化的高级示例
高级示例通过动态 Jito 提示(第 75 百分位)、自动计算单元计算、动态优先级费用和重试逻辑改进了简单版本。- @solana/web3.js
- @solana/kit
报告错误代码
复制
询问AI
import {
Connection,
TransactionMessage,
VersionedTransaction,
SystemProgram,
PublicKey,
Keypair,
LAMPORTS_PER_SOL,
ComputeBudgetProgram,
TransactionInstruction
} from '@solana/web3.js';
import bs58 from 'bs58';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];
async function getDynamicTipAmount(): Promise<number> {
try {
const response = await fetch('https://bundles.jito.wtf/api/v1/bundles/tip_floor');
const data = await response.json();
if (data && data[0] && typeof data[0].landed_tips_75th_percentile === 'number') {
const tip75th = data[0].landed_tips_75th_percentile;
// Use 75th percentile but minimum 0.0002 SOL
return Math.max(tip75th, 0.0002);
}
// Fallback if API fails or data is invalid
return 0.0002;
} catch (error) {
console.warn('Failed to fetch dynamic tip amount, using fallback:', error);
return 0.0002; // Fallback to minimum
}
}
async function sendWithSender(
keypair: Keypair,
instructions: TransactionInstruction[]
): Promise<string> {
const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY');
// Validate user hasn't included compute budget instructions
const hasComputeBudget = instructions.some(ix =>
ix.programId.equals(ComputeBudgetProgram.programId)
);
if (hasComputeBudget) {
throw new Error('Do not include compute budget instructions - they are added automatically');
}
// Create copy of instructions to avoid modifying the original array
const allInstructions = [...instructions];
// Get dynamic tip amount from Jito API (75th percentile, minimum 0.0002 SOL)
const tipAmountSOL = await getDynamicTipAmount();
const tipAccount = new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]);
console.log(`Using dynamic tip amount: ${tipAmountSOL} SOL`);
allInstructions.push(
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: tipAccount,
lamports: tipAmountSOL * LAMPORTS_PER_SOL,
})
);
// Get recent blockhash with context (Helius best practice)
const { value: blockhashInfo } = await connection.getLatestBlockhashAndContext('confirmed');
const { blockhash, lastValidBlockHeight } = blockhashInfo;
// Simulate transaction to get compute units
const testInstructions = [
ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
...allInstructions,
];
const testTransaction = new VersionedTransaction(
new TransactionMessage({
instructions: testInstructions,
payerKey: keypair.publicKey,
recentBlockhash: blockhash,
}).compileToV0Message()
);
testTransaction.sign([keypair]);
const simulation = await connection.simulateTransaction(testTransaction, {
replaceRecentBlockhash: true,
sigVerify: false,
});
if (!simulation.value.unitsConsumed) {
throw new Error('Simulation failed to return compute units');
}
// Set compute unit limit with minimum 1000 CUs and 10% margin (Helius best practice)
const units = simulation.value.unitsConsumed;
const computeUnits = units < 1000 ? 1000 : Math.ceil(units * 1.1);
// Get dynamic priority fee from Helius Priority Fee API
const priorityFee = await getPriorityFee(
connection,
allInstructions,
keypair.publicKey,
blockhash
);
// Add compute budget instructions at the BEGINNING (must be first)
allInstructions.unshift(
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee })
);
allInstructions.unshift(
ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits })
);
// Build final optimized transaction
const transaction = new VersionedTransaction(
new TransactionMessage({
instructions: allInstructions,
payerKey: keypair.publicKey,
recentBlockhash: blockhash,
}).compileToV0Message()
);
transaction.sign([keypair]);
// Send via Sender endpoint with retry logic
return await sendWithRetry(transaction, connection, lastValidBlockHeight);
}
async function getPriorityFee(
connection: Connection,
instructions: TransactionInstruction[],
payerKey: PublicKey,
blockhash: string
): Promise<number> {
try {
const tempTx = new VersionedTransaction(
new TransactionMessage({
instructions,
payerKey,
recentBlockhash: blockhash,
}).compileToV0Message()
);
const response = await fetch(connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: bs58.encode(tempTx.serialize()),
options: { recommended: true },
}],
}),
});
const data = await response.json();
return data.result?.priorityFeeEstimate ?
Math.ceil(data.result.priorityFeeEstimate * 1.2) : 50_000;
} catch {
return 50_000; // Fallback fee
}
}
async function sendWithRetry(
transaction: VersionedTransaction,
connection: Connection,
lastValidBlockHeight: number
): Promise<string> {
const maxRetries = 3;
// Frontend: Use HTTPS endpoint to avoid CORS issues
const endpoint = 'https://sender.helius-rpc.com/fast';
// Backend: Use regional HTTP endpoint closest to your servers
// const endpoint = 'http://slc-sender.helius-rpc.com/fast';
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
// Check blockhash validity
const currentHeight = await connection.getBlockHeight('confirmed');
if (currentHeight > lastValidBlockHeight) {
throw new Error('Blockhash expired');
}
// Send transaction via Sender endpoint
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [
Buffer.from(transaction.serialize()).toString('base64'),
{
encoding: "base64",
skipPreflight: true, // Required for Sender
maxRetries: 0 // Implement your own retry logic
}
]
})
});
const result = await response.json();
if (result.error) throw new Error(result.error.message);
console.log(`Transaction sent: ${result.result}`);
return await confirmTransaction(result.result, connection);
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed:`, error);
if (attempt === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
throw new Error('All retry attempts failed');
}
async function confirmTransaction(
signature: string,
connection: Connection
): Promise<string> {
const timeout = 15000;
const interval = 3000;
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
const status = await connection.getSignatureStatuses([signature]);
if (status?.value[0]?.confirmationStatus === "confirmed") {
return signature;
}
} catch (error) {
console.warn('Status check failed:', error);
}
await new Promise(resolve => setTimeout(resolve, interval));
}
throw new Error(`Transaction confirmation timeout: ${signature}`);
}
// Example usage following standard Helius docs pattern
export async function exampleUsage() {
const keypair = Keypair.fromSecretKey(new Uint8Array([/* your secret key */]));
// 1. Prepare your transaction instructions (USER ADDS THEIR INSTRUCTIONS HERE)
const instructions: TransactionInstruction[] = [
SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: new PublicKey("RECIPIENT_ADDRESS"),
lamports: 0.1 * LAMPORTS_PER_SOL,
}),
// Add more instructions as needed
];
// 2. Send with Sender (automatically adds tip + optimizations)
try {
const signature = await sendWithSender(keypair, instructions);
console.log(`Successful transaction: ${signature}`);
} catch (error) {
console.error('Transaction failed:', error);
}
}
export { sendWithSender };
报告错误代码
复制
询问AI
import { pipe } from "@solana/kit";
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
lamports,
getBase64EncodedWireTransaction,
createKeyPairSignerFromBytes,
address,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
import bs58 from 'bs58';
const TIP_ACCOUNTS = [
"4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
"D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ",
"9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
"5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
"2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
"2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
"wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
"3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
"4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
"4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];
async function getDynamicTipAmount(): Promise<number> {
try {
const response = await fetch('https://bundles.jito.wtf/api/v1/bundles/tip_floor');
const data = await response.json();
if (data && data[0] && typeof data[0].landed_tips_75th_percentile === 'number') {
const tip75th = data[0].landed_tips_75th_percentile;
// Use 75th percentile but minimum 0.0002 SOL
return Math.max(tip75th, 0.0002);
}
// Fallback if API fails or data is invalid
return 0.0002;
} catch (error) {
console.warn('Failed to fetch dynamic tip amount, using fallback:', error);
return 0.0002; // Fallback to minimum
}
}
async function sendWithSender(
privateKeyB58: string,
instructionBuilders: Array<(signer: any) => any>
): Promise<string> {
const rpc = createSolanaRpc('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY');
// Load signer from base58 private key
const ownerSigner = await createKeyPairSignerFromBytes(bs58.decode(privateKeyB58));
// Build user instructions
const userInstructions = instructionBuilders.map(builder => builder(ownerSigner));
// Get dynamic tip amount from Jito API (75th percentile, minimum 0.0002 SOL)
const tipAmountSOL = await getDynamicTipAmount();
const tipAccount = TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)];
console.log(`Using dynamic tip amount: ${tipAmountSOL} SOL`);
// Get recent blockhash with context
const { value: blockhashInfo } = await rpc.getLatestBlockhash().send();
const { blockhash, lastValidBlockHeight } = blockhashInfo;
// Create tip instruction
const tipInstruction = getTransferSolInstruction({
source: ownerSigner,
destination: address(tipAccount),
amount: lamports(BigInt(Math.floor(tipAmountSOL * 1_000_000_000))),
});
// Create transaction message for simulation with max compute units
const testInstructions = [
getSetComputeUnitLimitInstruction({ units: 1_400_000 }),
...userInstructions,
tipInstruction
];
const testTx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhashInfo, m),
(m) => appendTransactionMessageInstructions(testInstructions, m)
);
// Simulate transaction using RPC directly
const signedTestTx = await signTransactionMessageWithSigners(testTx);
const serializedTestTx = getBase64EncodedWireTransaction(signedTestTx);
const simulationResponse = await fetch('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: '1',
method: 'simulateTransaction',
params: [
serializedTestTx,
{ encoding: 'base64', commitment: 'processed' }
]
})
});
const simulation = await simulationResponse.json();
if (simulation.error || !simulation.result?.value?.unitsConsumed) {
throw new Error('Simulation failed to return compute units');
}
// Set compute unit limit with minimum 1000 CUs and 10% margin
const units = simulation.result.value.unitsConsumed;
const computeUnits = units < 1000 ? 1000 : Math.ceil(Number(units) * 1.1);
// Get dynamic priority fee
const priorityFee = await getPriorityFee(rpc, userInstructions, ownerSigner, blockhashInfo);
// Build final optimized transaction
const finalInstructions = [
getSetComputeUnitLimitInstruction({ units: computeUnits }),
getSetComputeUnitPriceInstruction({ microLamports: priorityFee }),
...userInstructions,
tipInstruction
];
const tx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(ownerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhashInfo, m),
(m) => appendTransactionMessageInstructions(finalInstructions, m)
);
// Send via Sender endpoint with retry logic
return await sendWithRetry(tx, rpc, lastValidBlockHeight);
}
async function getPriorityFee(
rpc: any,
instructions: any[],
payerSigner: any,
blockhashInfo: any
): Promise<number> {
try {
const tempTx = pipe(
createTransactionMessage({ version: 0 }),
(m) => setTransactionMessageFeePayerSigner(payerSigner, m),
(m) => setTransactionMessageLifetimeUsingBlockhash(blockhashInfo, m),
(m) => appendTransactionMessageInstructions(instructions, m)
);
const signedTempTx = await signTransactionMessageWithSigners(tempTx);
const serializedTx = getBase64EncodedWireTransaction(signedTempTx);
const response = await fetch('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY', {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTx,
options: { recommended: true },
}],
}),
});
const data = await response.json();
return data.result?.priorityFeeEstimate ?
Math.ceil(data.result.priorityFeeEstimate * 1.2) : 50_000;
} catch {
return 50_000; // Fallback fee
}
}
async function sendWithRetry(
transaction: any,
rpc: any,
lastValidBlockHeight: bigint
): Promise<string> {
const maxRetries = 3;
// Frontend: Use HTTPS endpoint to avoid CORS issues
const endpoint = 'https://sender.helius-rpc.com/fast';
// Backend: Use regional HTTP endpoint closest to your servers
// const endpoint = 'http://slc-sender.helius-rpc.com/fast';
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
// Check blockhash validity
const { value: currentHeight } = await rpc.getBlockHeight('confirmed').send();
if (currentHeight > lastValidBlockHeight) {
throw new Error('Blockhash expired');
}
// Sign and serialize transaction
const signedTx = await signTransactionMessageWithSigners(transaction);
const base64Tx = getBase64EncodedWireTransaction(signedTx);
// Send transaction via Sender endpoint
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: "2.0",
id: Date.now().toString(),
method: "sendTransaction",
params: [
base64Tx,
{
encoding: "base64",
skipPreflight: true, // Required for Sender
maxRetries: 0 // Implement your own retry logic
}
]
})
});
const result = await response.json();
if (result.error) throw new Error(result.error.message);
console.log(`Transaction sent: ${result.result}`);
return await confirmTransaction(result.result, rpc);
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed:`, error);
if (attempt === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
throw new Error('All retry attempts failed');
}
async function confirmTransaction(
signature: string,
rpc: any
): Promise<string> {
const timeout = 15000;
const interval = 3000;
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
try {
const status = await rpc.getSignatureStatuses([signature]).send();
if (status?.value[0]?.confirmationStatus === "confirmed") {
return signature;
}
} catch (error) {
console.warn('Status check failed:', error);
}
await new Promise(resolve => setTimeout(resolve, interval));
}
throw new Error(`Transaction confirmation timeout: ${signature}`);
}
// Example usage following standard Helius docs pattern
export async function exampleUsage() {
const privateKeyB58 = 'YOUR_PRIVATE_KEY_BASE58';
// 1. Prepare your transaction instruction builders (USER ADDS THEIR INSTRUCTIONS HERE)
const instructionBuilders = [
(signer: any) => getTransferSolInstruction({
source: signer,
destination: address("RECIPIENT_ADDRESS"),
amount: lamports(100_000_000n), // 0.1 SOL
}),
// Add more instruction builders as needed
];
// 2. Send with Sender (automatically adds tip + optimizations)
try {
const signature = await sendWithSender(privateKeyB58, instructionBuilders);
console.log(`Successful transaction: ${signature}`);
} catch (error) {
console.error('Transaction failed:', error);
}
}
export { sendWithSender };
最佳实践
端点选择
- 前端应用程序:使用
https://sender.helius-rpc.com/fast以避免 CORS 预检失败。此端点会自动路由到最近的位置以获得最佳性能。 - 后端应用程序:选择最接近您的基础设施的区域 HTTP 端点以获得最佳性能
连接预热
- 在空闲时间超过 1 分钟时使用
/ping端点 - 实施定期 ping 调用(每 30-60 秒)以保持连接预热
- 在高频交易会话开始前预热连接
交易设置
- 使用
skipPreflight: true和maxRetries: 0 - 实现你自己的重试逻辑
- 向指定账户包含至少 0.0002 SOL 的小费
- 使用
'confirmed'承诺获取区块哈希 - 设置适当的计算单元限制
速率限制和扩展
- 默认速率限制:每秒15笔交易
- 无积分消耗:发送方交易不消耗计划中的API积分
- 专业计划升级:专业计划用户可以请求显著的速率限制增加,以支持高吞吐量交易应用
使用 API 密钥认证的自定义 TPS
本节仅在您获得了更高的 TPS 限制并从 Helius 团队收到 API 密钥时相关。标准用户可以跳过本节。
- 前端/浏览器应用程序
- 后端/服务器应用程序
报告错误代码
复制
询问AI
https://sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
报告错误代码
复制
询问AI
http://slc-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://ewr-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://lon-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://fra-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://ams-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://sg-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
http://tyo-sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY
报告错误代码
复制
询问AI
const SENDER_ENDPOINT = 'https://sender.helius-rpc.com/fast?api-key=YOUR_SENDER_API_KEY';
const response = await fetch(SENDER_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now().toString(),
method: 'sendTransaction',
params: [
base64Transaction,
{ encoding: 'base64', skipPreflight: true, maxRetries: 0 }
]
})
});
还没有自定义 TPS 限制?如果您的应用程序需要超过 15 TPS,请在此请求更高的限制。
支持和扩展
对于需要更高吞吐量的生产部署:请求更高的 TPS 限制
需要超过 15 TPS?请填写我们的请求表格。专业计划用户可以获得高频交易应用程序的显著速率限制升级。
- 通过 Helius Dashboard 联系支持
- 加入我们的 Discord 社区 以获得实时帮助