> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cách gửi giao dịch Solana

> Hướng dẫn từng bước để xây dựng quy trình gửi giao dịch Solana mạnh mẽ, đạt chuẩn production. Tìm hiểu cách tối ưu hóa tài nguyên tính toán, phí ưu tiên và chiến lược xác nhận.

<Tip>
  Đây là phương thức gửi giao dịch **cơ bản** — tính phí theo mỗi lần gửi và phù hợp nhất khi
  độ tin cậy quan trọng hơn tốc độ thuần túy (thanh toán, ví, ứng dụng). Nếu bạn đang
  giao dịch và cần độ trễ thấp nhất, hãy sử dụng [Helius
  Sender](/docs/vi/sending-transactions/sender).
</Tip>

Tự xây dựng logic gửi giao dịch là cách tốt nhất để đảm bảo hiệu suất, khả năng kiểm soát và độ tin cậy tối đa cho ứng dụng. Mặc dù [Helius SDK](/docs/vi/sdks) cung cấp một lớp bao tiện lợi để bắt đầu, bạn vẫn nên tìm hiểu và triển khai quy trình thủ công này cho các hệ thống production.

Hướng dẫn này sẽ trình bày các bước cần thiết để bạn tự xây dựng giải pháp.

### Quy trình thủ công

Gửi giao dịch theo cách thủ công bao gồm các bước sau:

<Steps>
  <Step title="Build the Initial Transaction">
    Tập hợp các chỉ thị và ký giao dịch để có thể mô phỏng giao dịch đó.
  </Step>

  <Step title="Optimize Compute Units">
    Mô phỏng giao dịch để xác định chính xác số CU cần thiết và thêm một khoảng dự phòng nhỏ.
  </Step>

  <Step title="Add Priority Fees">
    Lấy mức phí ước tính từ Helius Priority Fee API và thêm phí đó vào giao dịch.
  </Step>

  <Step title="Send and Re-broadcast">
    Gửi giao dịch cuối cùng và triển khai chiến lược thăm dò mạnh mẽ để xử lý việc xác nhận.
  </Step>
</Steps>

<Info>
  Các Helius SDK đều có mã nguồn mở. Bạn có thể xem mã nguồn của phương thức `sendSmartTransaction` trong [TypeScript SDK](https://github.com/helius-labs/helius-sdk) và [Rust SDK](https://github.com/helius-labs/helius-rust-sdk) để tham khảo cách triển khai quy trình này đạt chuẩn production.
</Info>

### 1. Xây dựng giao dịch ban đầu

Trước tiên, hãy tập hợp tất cả chỉ thị bạn muốn đưa vào giao dịch. Sau đó, tạo một đối tượng `Transaction` hoặc `VersionedTransaction`. Bạn cũng cần truy xuất một blockhash gần đây.

Ví dụ này chuẩn bị một giao dịch có phiên bản. Ở giai đoạn này, bạn cũng phải ký giao dịch để có thể mô phỏng giao dịch đó trong bước tiếp theo.

```typescript theme={"system"}
import {
  Connection,
  Keypair,
  TransactionMessage,
  VersionedTransaction,
  SystemProgram,
  LAMPORTS_PER_SOL,
} from "@solana/web3.js";

const connection = new Connection("YOUR_RPC_URL");
const fromKeypair = Keypair.generate(); // Assume this is funded
const toPubkey = Keypair.generate().publicKey;

// 1. Build your instructions
const instructions = [
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toPubkey,
    lamports: 0.001 * LAMPORTS_PER_SOL,
  }),
];

// 2. Get a recent blockhash
const { blockhash } = await connection.getLatestBlockhash();

// 3. Compile the transaction message
const messageV0 = new TransactionMessage({
  payerKey: fromKeypair.publicKey,
  recentBlockhash: blockhash,
  instructions,
}).compileToV0Message();

// 4. Create and sign the transaction
const transaction = new VersionedTransaction(messageV0);
transaction.sign([fromKeypair]);
```

### 2. Tối ưu hóa mức sử dụng đơn vị tính toán (CU)

Để tránh lãng phí phí hoặc khiến giao dịch thất bại, bạn nên đặt giới hạn đơn vị tính toán (CU) chính xác nhất có thể. Bạn có thể thực hiện việc này bằng cách mô phỏng giao dịch qua phương thức RPC [`simulateTransaction`](/docs/vi/api-reference/rpc/http/simulatetransaction).

Phương pháp tốt nhất là mô phỏng trước với giới hạn CU cao để đảm bảo chính quá trình mô phỏng thành công, sau đó dùng `unitsConsumed` từ phản hồi để đặt giới hạn thực tế.

```typescript theme={"system"}
import { ComputeBudgetProgram } from "@solana/web3.js";

// Create a test transaction with a high compute limit to ensure simulation succeeds
const testInstructions = [
    ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
    ...instructions, // Your original instructions
];
const testMessage = new TransactionMessage({
    payerKey: fromKeypair.publicKey,
    recentBlockhash: blockhash,
    instructions: testInstructions,
}).compileToV0Message();
const testTransaction = new VersionedTransaction(testMessage);
testTransaction.sign([fromKeypair]);

// Simulate the transaction to get the exact CUs consumed
const { value: simulationResult } = await connection.simulateTransaction(testTransaction);

if (!simulationResult.unitsConsumed) {
  throw new Error("Simulation failed to return unitsConsumed");
}

// Add a 10% buffer to the CU estimate
const computeUnitLimit = Math.ceil(simulationResult.unitsConsumed * 1.1);

// Create the instruction to set the CU limit
const setCuLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({
    units: computeUnitLimit,
});
```

Giờ đây, bạn đã có một chỉ thị đặt giới hạn tính toán chính xác. Bạn sẽ thêm chỉ thị này vào giao dịch cuối cùng.

### 3. Đặt mức phí ưu tiên phù hợp

Tiếp theo, hãy xác định mức phí ưu tiên tối ưu để thêm vào giao dịch. Sử dụng [Priority Fee API](/docs/vi/priority-fee-api) của Helius là cách tốt nhất để nhận mức ước tính theo thời gian thực dựa trên điều kiện mạng hiện tại.

Bạn cần gọi phương thức RPC `getPriorityFeeEstimate`. Để có khả năng được đưa vào cao nhất thông qua các kết nối có stake của Helius, hãy sử dụng tùy chọn `recommended: true`.

```typescript theme={"system"}
// The transaction needs to be serialized and base58 encoded
const serializedTransaction = bs58.encode(transaction.serialize());

const response = await fetch("YOUR_RPC_URL", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        jsonrpc: "2.0",
        id: "1",
        method: "getPriorityFeeEstimate",
        params: [
            {
                // Pass the serialized transaction
                transaction: serializedTransaction, 
                // Use 'recommended' for Helius's staked connections
                options: { recommended: true },
            },
        ],   
    }),
});
const data = await response.json();

if (!data.result || !data.result.priorityFeeEstimate) {
    throw new Error("Failed to get priority fee estimate");
}

const priorityFeeEstimate = data.result.priorityFeeEstimate;

// Create the instruction to set the priority fee
const setPriorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: priorityFeeEstimate,
});
```

### 4. Xây dựng, gửi và xác nhận

Bây giờ, hãy tập hợp giao dịch cuối cùng với các chỉ thị ngân sách tính toán mới, gửi giao dịch và triển khai cơ chế thăm dò mạnh mẽ để xác nhận giao dịch đã được ghi nhận.

<Warning>
  Không dựa vào logic thử lại mặc định của nhà cung cấp RPC (`maxRetries` trong [`sendTransaction`](/docs/vi/api-reference/rpc/http/sendtransaction)). Mặc dù các kết nối có stake của Helius chuyển tiếp giao dịch trực tiếp đến leader, giao dịch vẫn có thể bị loại bỏ. Bạn phải triển khai logic phát lại riêng để đảm bảo xác nhận đáng tin cậy.
</Warning>

Một mô hình phổ biến là định kỳ gửi lại cùng một giao dịch cho đến khi blockhash hết hạn. **Chỉ ký lại giao dịch nếu bạn cũng truy xuất một blockhash mới.** Việc ký lại bằng cùng một blockhash có thể khiến các giao dịch trùng lặp được xác nhận.

```typescript theme={"system"}
// 1. Add the new instructions to your original set
const finalInstructions = [
  setCuLimitInstruction,
  setPriorityFeeInstruction,
  ...instructions,
];

// 2. Re-build and re-sign the transaction with the final instructions
const { blockhash: latestBlockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();

const finalMessage = new TransactionMessage({
  payerKey: fromKeypair.publicKey,
  recentBlockhash: latestBlockhash,
  instructions: finalInstructions,
}).compileToV0Message();

const finalTransaction = new VersionedTransaction(finalMessage);
finalTransaction.sign([fromKeypair]);

// 3. Send the transaction
const signature = await connection.sendTransaction(finalTransaction, {
  skipPreflight: true, // Optional: useful for bypassing client-side checks
});

// 4. Implement a polling loop to confirm the transaction
let confirmed = false;
while (!confirmed) {
    const statuses = await connection.getSignatureStatuses([signature]);
    const status = statuses && statuses.value && statuses.value[0];

    if (status && (status.confirmationStatus === 'confirmed' || status.confirmationStatus === 'finalized')) {
        console.log('Transaction confirmed!');
        confirmed = true;
    }

    // Check if the blockhash has expired
    const currentBlockHeight = await connection.getBlockHeight();
    if (currentBlockHeight > lastValidBlockHeight) {
        console.log('Blockhash expired, transaction failed.');
        break;
    }
    
    // Wait for a short period before polling again
    await new Promise(resolve => setTimeout(resolve, 2000)); 
}
```

Ví dụ này cung cấp một vòng lặp thăm dò cơ bản. Một ứng dụng đạt chuẩn production sẽ cần logic phức tạp hơn, bao gồm xử lý các trạng thái xác nhận khác nhau và những trường hợp hết thời gian chờ có thể xảy ra.

## Bảo vệ khỏi các cuộc tấn công sandwich

Để định tuyến giao dịch tránh xa các validator có liên hệ về mặt thống kê với các cuộc tấn công sandwich, hãy thêm tham số truy vấn `mev-protect=true` vào URL RPC — không cần thay đổi logic giao dịch:

```
https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY&mev-protect=true
```

<Card title="MEV Protect" icon="shield-halved" href="/docs/vi/sending-transactions/mev-protect">
  Tìm hiểu cách MEV Protect hoạt động, các phương thức được hỗ trợ và những đánh đổi liên quan.
</Card>

## Nhận hoàn tiền từ giao dịch

Bạn có thể chọn tham gia để nhận một phần MEV do các giao dịch của mình tạo ra, được tự động thanh toán bằng SOL — không cần thay đổi logic giao dịch.

<Card title="Transaction Rebates" icon="coins" href="/docs/vi/sending-transactions/backrun-rebates">
  Thêm một tham số vào các lệnh gọi `sendTransaction` để bắt đầu nhận khoản hoàn tiền bằng SOL.
</Card>

## Các phương thức liên quan

<CardGroup cols={2}>
  <Card title="sendTransaction" href="/docs/vi/api-reference/rpc/http/sendtransaction">
    Gửi một giao dịch đã ký đến mạng
  </Card>

  <Card title="simulateTransaction" href="/docs/vi/api-reference/rpc/http/simulatetransaction">
    Mô phỏng giao dịch để ước tính số đơn vị tính toán
  </Card>

  <Card title="getSignatureStatuses" href="/docs/vi/api-reference/rpc/http/getsignaturestatuses">
    Kiểm tra trạng thái xác nhận của các giao dịch
  </Card>

  <Card title="getLatestBlockhash" href="/docs/vi/api-reference/rpc/http/getlatestblockhash">
    Lấy một blockhash gần đây để ký giao dịch
  </Card>

  <Card title="getBlockHeight" href="/docs/vi/api-reference/rpc/http/getblockheight">
    Lấy chiều cao khối hiện tại để kiểm tra thời điểm hết hạn
  </Card>
</CardGroup>
