提交交易
如何提交交易
Astralane 为您的需求提供了多种选项,以下是我们为交易发送提供的一些 RPC 方法。
sendTransation
此 RPC 调用与所有 Solana 库完全兼容,使其成为您现有工作流程的简单替代品。它通过我们的合作伙伴 SWQoS 客户端(包括 Jito 和 Paladin(更高的最低提示))进行路由,确保优化交易处理和最大可靠性。
只需将 URL 插入您要放置 RPC URL 的位置,然后像平常一样发送您的 txns。唯一的变化是向提示添加指令。
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
fn send_tx_tipped(
ixs: &mut Vec<Instruction>,
signer: &Keypair,
rpc_client: &RpcClient
) {
let tip_ix = system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT);
ixs.push(tip_ix);
let blockhash = rpc_client.get_latest_blockhash().unwrap();
let tx = Transaction::new_signed_with_payer(ixs, Some(&signer.pubkey()), &[signer], blockhash);
rpc_client.send_transaction(&tx).unwrap();
}
请注意,sendTransaction 端点支持 max_retries: None 和 min_context_slot: None 功能,这对于不希望我们的质押节点重试其交易的交易者非常有用。请联系我们以获取有关理想用例的更多信息。
**新 - 如果最小小费满足发送给 Paladin 的最小小费要求,端点也可用于向 Paladin 广播。阅读下面的更多优势。。
sendBundle
如果您的操作依赖于原子交易执行,那么请使用我们的 sendBundle 端点发送原子执行交易。
在单个原子包中最多发送 4 个交易。这些交易按顺序执行,确保准确性和可靠性。如果任何交易失败,整个包都会被恢复——保证一致性并消除部分故障。
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
async fn send_bundle(
ixs: &mut Vec<Instruction>,
signer: &Keypair,
client: reqwest::Client,
blockhash: Hash,
url: String,
) {
let tip_ix = system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT);
ixs.push(tip_ix);
let tx = Transaction::new_signed_with_payer(ixs, Some(&signer.pubkey()), &[signer], blockhash);
let encoded_tx = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(tx).unwrap());
let response = client
.post(url)
.header("api_key", "xxx")
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [[encoded_tx]],
}))
.send()
.await;
}
package main
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/gagliardetto/solana-go/programs/system"
"log"
"net/http"
"time"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
)
func main() {
payerPrivateKeyBase58 := "YOUR_WALLET_PRIVATE_KEY"
astralaneTipAddressBase58 := "astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"
rpcEndpoint := "DM_US_FOR_TRIAL_RPC_ENDPOINTS"
astralaneEndpoint := "http://fr.gateway.astralane.io/iris?api-key=YOUR_ASTRALANE_API_KEY"
signer, err := solana.PrivateKeyFromBase58(payerPrivateKeyBase58)
if err != nil {
log.Fatalf("Failed to load private key: %v", err)
}
client := rpc.New(rpcEndpoint)
recentBlockhash, err := client.GetLatestBlockhash(context.Background(), rpc.CommitmentFinalized)
if err != nil {
log.Fatalf("Failed to get recent blockhash: %v", err)
}
astralaneTipAddress, err := solana.PublicKeyFromBase58(astralaneTipAddressBase58)
if err != nil {
log.Fatalf("Failed to decode astralane tip address: %v", err)
}
tx, err := solana.NewTransaction(
[]solana.Instruction{
system.NewTransferInstruction(
200_000,
signer.PublicKey(),
astralaneTipAddress,
).Build(),
},
recentBlockhash.Value.Blockhash,
solana.TransactionPayer(signer.PublicKey()),
)
if err != nil {
log.Fatalf("Failed to create transaction: %v", err)
}
if _, err := tx.Sign(func(key solana.PublicKey) *solana.PrivateKey {
return &signer
}); err != nil {
log.Fatalf("Failed to sign transaction: %v", err)
}
spew.Dump(tx)
out, err := tx.MarshalBinary()
if err != nil {
log.Fatalf("Marshaling to binary failed: %v", err)
}
encodedTx := base64.StdEncoding.EncodeToString(out)
decoded, err := base64.StdEncoding.DecodeString(encodedTx)
if err != nil {
log.Fatalf("Sanity check decode failed: %v", err)
}
if !bytes.Equal(decoded, out) {
log.Fatalf("Sanity check failed: decoded transaction does not match original binary")
}
payload := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": []interface{}{
[]string{encodedTx},
},
}
response, err := sendBundleRequest(astralaneEndpoint, payload)
if err != nil {
log.Fatalf("Bundle RPC failed: %v", err)
}
log.Printf("Bundle RPC response: %s", response)
}
func sendBundleRequest(endpoint string, payload map[string]interface{}) (string, error) {
jsonData, err := json.Marshal(payload)
if err != nil {
return "", fmt.Errorf("Failed to marshal JSON: %w", err)
}
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Post(endpoint, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("Request to Bundle RPC failed: %w", err)
}
defer resp.Body.Close()
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("Failed to decode Bundle RPC response: %w", err)
}
responseBytes, _ := json.MarshalIndent(result, "", " ")
return string(responseBytes), nil
}
Request:
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendBundle",
"params": [
"base64_encoded_txn1",
"base64_encoded_txn2"
"base64_encoded_txn3"
{
"encoding": "base64",
"mevProtect": true
}
]
}
Response:
您的交易签名列表
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"37Dxw2nJYw3T8JVqenPQMf39VJ9CNZYCyQm67b6nRj6fa6UjQ1UuLqFvh3wJ2G7LcMuZn4oq5kDt2A2CEXfi8D8"
]
}
Note: MAX_TRANSACTIONS_IN_BUNDLE = 4
sendIdeal
非常适合狙击手!由于验证器分为 JITO 验证器和普通验证器,交易者经常在 jito 小费上花费更多和优先费用上花费更多之间产生矛盾。持久随机数提供了一种缓解此问题的方法。
我们的 sendIdeal RPC 方法接受两笔交易:
一笔交易具有高优先级费用 + 最低小费
另一笔交易具有高小费 + 低优先级费用
我们通过先进的 SWQoS 和捆绑管道路由它们。使用持久随机数,一旦一笔交易完成,另一笔交易就会自动取消 — 确保最佳效率和成本节约。
如果您不想自己管理持久随机数帐户,我们还为此提供托管服务,我们为您使用的每个 api 密钥创建一个随机数帐户,您可以使用我们的 getNonce rpc 调用查询它们。请按照以下集成步骤来充分利用此功能:
步骤 1:生成Nonce指令
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{EncodableKey, Keypair, Signer};
async fn get_nonce(
client: reqwest::Client,
url: String,
auth_key: String,
) {
let response = client
.post(url)
.header("api_key", "xxx")
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "getNonce",
"params": [api_key], // provided during onboarding
}))
.send()
.await;
let result = response["result"].clone();
let nonce = result["nonce"].as_str().unwrap();
let nonce_account = Pubkey::from_str(result["nonceAccount"].as_str().unwrap()).unwrap();
let nonce_authority =
Pubkey::from_str(result["nonceAuthority"].as_str().unwrap()).unwrap();
let nonce_as_hash = Hash::from_str(nonce).unwrap();
}
如果您已经有一个现成的 nonce 帐户,则只需传入您的 nonce 帐户,您只需传入您的 nonce 帐户公钥即可,而不必传入 API 密钥。响应仍将包含您解析的 nonce。
要使用这个 nonce,只需将提前 nonce 指令作为交易中的第一个指令即可。
步骤 2:生成交易并在提交前进行部分签名
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
async fn send_ideal(
signer: &Keypair,
client: reqwest::Client,
nonce: Hash,
instructions: Vec<Instruction>,
nonce_authority: &Pubkey,
nonce_account: &Pubkey,
) {
// add advance nonce instruction
let advance_nonce = solana_sdk::system_instruction::advance_nonce_account(nonce_account, nonce_authority);
let low_tip_high_fee_ixs = vec![
advance_nonce.clone(),
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
10 * MICRO_LAMPORTS_PER_LAMPORTS,
),
// add your instructions here
solana_sdk::system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT),
];
let high_tip_low_fee_ixs = vec![
advance_nonce,
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
100,
),
// add your instructions here
solana_sdk::system_instruction::transfer(&signer.pubkey(), &TIP, 100 * MIN_TIP_AMOUNT),
];
//add high transaction priority fee and min tip
let mut low_tip_high_fee_tx = Transaction::new_with_payer(&low_tip_high_fee_ixs, Some(&signer.pubkey()));
low_tip_high_fee_tx.partial_sign(&[&signer], nonce);
let mut high_tip_low_fee_tx = Transaction::new_with_payer(&high_tip_low_fee_ixs, Some(&signer.pubkey()));
high_tip_low_fee_tx.partial_sign(&[&signer], nonce);
let low_tip_high_fee_tx_encoded = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(low_tip_high_fee_tx).unwrap());
let high_tip_low_fee_tx_encoded = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(high_tip_low_fee_tx).unwrap());
let response = client
.post(url)
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "sendIdeal",
"params": [[low_tip_high_fee_tx_encoded, high_tip_low_fee_tx_encoded]],
}))
.send()
.await;
}
使用 Astralane 的托管 nonce 账户时,请确保使用 partial_sign 方法签署交易。如果您不使用托管 nonce 账户,请继续使用标准签名方法。
**新 - 如果最小小费满足发送给 Paladin 的最小小费要求,则端点也可用于向 Paladin 广播。阅读下面的更多优势。
TypeScript での sendIdeal エンドポイントの使用例を以下に示します。
import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL,
ComputeBudgetProgram,
} from '@solana/web3.js';
import * as bs58 from 'bs58';
async sendTransTest() {
try {
const result = await fetch(
`http://fr.gateway.astralane.io/iris?api-key=<api-key>`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'getNonce',
params: [
'api-key',
],
}),
},
);
const res = await result.json();
const data = res as any;
const nonceAccount = new PublicKey(data.result.nonceAccount);
const nonceAuthority = new PublicKey(data.result.nonceAuthority);
const nonce = data.result.nonce;
const advanceNonce = SystemProgram.nonceAdvance({
noncePubkey: nonceAccount,
authorizedPubkey: nonceAuthority,
});
const secretKey = Keypair.fromSecretKey(
bs58.default.decode(
'wallet-private-key',
),
);
const wallet = secretKey;
//Tip account
const toPublicKey = new PublicKey(
'astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm',
);
const MIN_TIP_AMOUNT = 100000;
const lowTipHighFeeIx = [
advanceNonce,
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1 * 100000,
}),
SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: toPublicKey,
lamports: MIN_TIP_AMOUNT,
}),
];
const HighTipLowFeeIx = [
advanceNonce,
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1 * 100,
}),
SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: toPublicKey,
lamports: 100 * MIN_TIP_AMOUNT,
}),
];
const htlfTransaction = new Transaction().add(...HighTipLowFeeIx);
htlfTransaction.recentBlockhash = nonce;
htlfTransaction.feePayer = wallet.publicKey;
htlfTransaction.partialSign(wallet);
const highTipLowFeeEncoded = Buffer.from(
htlfTransaction.serialize({
requireAllSignatures: false,
verifySignatures: false,
}),
).toString('base64');
const lthfTransaction = new Transaction().add(...lowTipHighFeeIx);
lthfTransaction.recentBlockhash = nonce;
lthfTransaction.feePayer = wallet.publicKey;
lthfTransaction.partialSign(wallet);
const lowTipHighFeeEncoded = Buffer.from(
lthfTransaction.serialize({
requireAllSignatures: false,
verifySignatures: false,
}),
).toString('base64');
const final = await fetch(
`http://fr.gateway.astralane.io/iris?api-key=<api-key>`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'sendIdeal',
params: [[highTipLowFeeEncoded, lowTipHighFeeEncoded]],
}),
},
);
const finalResult = await final.json();
console.log(finalResult);
return lowTipHighFeeEncoded;
} catch (error) {
console.log(error);
}
}
さらに詳しい説明については、何が起こっているかを段階的に説明した Rust ドキュメントを参照してください。
Request
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendIdeal",
"params": [
"transction_with_large_tip_low_priority_fee",
"transaction_with_large_priority_fee_low_tip"
{
"encoding": "base64"
}
]
}
Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"<signature A>",
"<signature B>"
]
}
您的交易的延迟性能将取决于当前的网络动态。请通过电报联系我们,获取有关您操作的理想设置的建议
sendPaladin (Beta)
步骤 1:跟踪圣骑士领袖 由于并非所有插槽都有圣骑士验证器,因此我们提供了一个圣骑士领袖跟踪器端点,可用于了解哪些插槽有圣骑士领袖。以下是跟踪器集成的一些一般准则,可根据领袖信息动态发送交易:
获取当前时期的所有 Palidator 公钥
⚔️ GET /api/palidators
[
"Ss...Z77",
"ACv...mi",
"7Z...Z84",
]
获得下一任 Palidator 领导者职位
⚔️ GET /api/next_palidator
{
"pubkey": "Csd...def",
"leader_slot": 42424242,
"context_slot": 42424242
}
在指定时间段内或之后获取下一任领导者 Palidator
⚔️ GET /api/next_palidator/{slot}
{
"pubkey": "Csd...def",
"leader_slot": 42424242,
"context_slot": 42424242
}
发送给圣骑士验证器的 txns 的最小限制为 10 lampors/cu。
第二步:制作圣骑士交易
使用 send_palladin
方法在这些时段内发送交易。在此端点上发送交易时,请确保遵守最低小费要求和最低优先费用要求。
发送交易时支持两种模式 Fail on revert: True / False
发送到此端点的所有交易都会经过小型拍卖,排序将基于:
优先费用
任何决胜局都将通过提示澳大利亚 IP 地址来决定
获胜交易将通过圣骑士端口发送。在 failOnRevert: false
的情况下,如果您的交易未能赢得拍卖,它们将通过 SwQOS / JITO 发送。
如果 failOnRevert 为 true
,这些交易将仅发送给 Palidators,如果该位置不在圣骑士领袖附近,这些交易将被丢弃。
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendPaladin",
"params": [
"<base 64 tx>",
{
"failOnRevert": "false"
}
]
}
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"<signature A>",
]
}
为了有效使用此功能,请务必使用我们的 Paladin Leader API 端点来跟踪活跃领导者和时段时间,并相应地调整小费/费用。通过专用端点更新您的配置,以实现最佳成本控制。
需要帮助吗?
Last updated