> ## 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.

# Solana 트랜잭션 보내는 방법

> 견고하고 프로덕션 수준의 Solana 트랜잭션 보내기 워크플로를 구축하기 위한 단계별 가이드입니다. 컴퓨팅 최적화, 우선 수수료 및 확인 전략에 대해 알아보세요.

<Tip>
  이것은 **기본적인** 트랜잭션 전송 경로입니다 — 전송당 청구되며 신뢰성이 순수 속도보다 중요할 때 (결제, 지갑, 앱)에 적합합니다. 거래 시 지연을 최소화해야 한다면, 대신 [Helius
  Sender](/docs/ko/sending-transactions/sender)를 사용하세요.
</Tip>

직접 트랜잭션 전송 로직을 구축하는 것은 애플리케이션의 최대 성능, 제어 및 신뢰성을 보장하는 최고의 방법입니다. [Helius SDK](/docs/ko/sdks)는 시작하기 위한 편리한 래퍼를 제공하지만, 이 수동 워크플로를 이해하고 구현하는 것이 프로덕션 시스템에 강력히 추천됩니다.

이 가이드는 직접 솔루션을 구축하기 위한 필수 단계를 안내합니다.

### 수동 워크플로

수동으로 트랜잭션을 보내는 것은 다음 단계를 포함합니다:

<Steps>
  <Step title="초기 트랜잭션 빌드">
    지침을 모으고 트랜잭션에 서명하여 시뮬레이션할 수 있도록 합니다.
  </Step>

  <Step title="컴퓨트 유닛 최적화">
    트랜잭션을 시뮬레이션하여 필요한 정확한 CU를 결정하고 작은 버퍼를 추가합니다.
  </Step>

  <Step title="우선 수수료 추가">
    Helius 우선 수수료 API에서 수수료 견적을 받아 트랜잭션에 추가합니다.
  </Step>

  <Step title="전송 및 재전송">
    최종 트랜잭션을 보내고 확정을 처리하는 견고한 폴링 전략을 구현합니다.
  </Step>
</Steps>

<Info>
  Helius SDK는 오픈 소스입니다. 이 워크플로의 프로덕션 수준 구현을 보려면 [Node.js SDK](https://github.com/helius-labs/helius-sdk) 및 [Rust SDK](https://github.com/helius-labs/helius-rust-sdk)에서 `sendSmartTransaction` 메서드의 기본 코드를 볼 수 있습니다.
</Info>

### 1. 초기 트랜잭션 빌드

먼저 트랜잭션에 포함할 모든 지침을 모으세요. 그런 다음 `Transaction` 또는 `VersionedTransaction` 객체를 생성하세요. 최근 블록 해시도 가져와야 합니다.

이 예시는 버전 트랜잭션을 준비합니다. 이 단계에서는 또한 서명하여 다음 단계에서 시뮬레이션할 수 있도록 해야 합니다.

```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. 컴퓨트 유닛 (CU) 사용 최적화

수수료 낭비를 피하거나 트랜잭션 실패를 방지하려면 컴퓨트 유닛 (CU) 제한을 최대한 정확하게 설정해야 합니다. [`simulateTransaction`](/docs/ko/api-reference/rpc/http/simulatetransaction) RPC 메서드를 사용하여 트랜잭션을 시뮬레이션함으로써 이를 수행할 수 있습니다.

시뮬레이션 자체가 성공하도록 하기 위해 높은 CU 제한으로 먼저 시뮬레이션하는 것이 최상의 실습이며, 그런 다음 응답에서 얻은 `unitsConsumed`를 사용하여 실제 제한을 설정합니다.

```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,
});
```

이제 컴퓨트 제한을 정확하게 설정하는 지침이 있습니다. 최종 트랜잭션에 추가할 것입니다.

### 3. 적절한 우선 수수료 설정

다음으로, 트랜잭션에 추가할 최적의 우선 수수료를 결정하세요. Helius [Priority Fee API](/docs/ko/priority-fee-api)를 사용하여 현재 네트워크 상태를 기반으로 실시간 견적을 얻는 것이 가장 좋은 방법입니다.

`getPriorityFeeEstimate` RPC 메서드를 호출해야 합니다. Helius의 스테이크된 연결을 통한 포함 가능성을 높이기 위해 `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. 빌드, 전송 및 확인

이제 새로운 컴퓨트 예산 지침으로 최종 트랜잭션을 조합하고, 전송하며, 확정되었는지 확인하기 위한 견고한 폴링 메커니즘을 구현하세요.

<Warning>
  RPC 공급자의 기본 재시도 로직 (`maxRetries` in [`sendTransaction`](/docs/ko/api-reference/rpc/http/sendtransaction))에 의존하지 마세요. Helius의 스테이킹된 연결은 트랜잭션을 리더에게 직접 전달하지만 여전히 드롭될 수 있습니다. 신뢰할 수 있는 확인을 위해 직접 재전송 로직을 구현해야 합니다.
</Warning>

일반적인 패턴은 블록 해시가 만료될 때까지 동일한 트랜잭션을 주기적으로 다시 보내는 것입니다. **새 블록 해시를 가져오는 경우에만 트랜잭션에 다시 서명하세요.** 동일한 블록 해시로 다시 서명하면 중복 트랜잭션이 확정될 수 있습니다.

```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)); 
}
```

이 예시는 기본적인 폴링 루프를 제공합니다. 프로덕션 등급의 애플리케이션은 서로 다른 확인 상태 및 잠재적 타임아웃을 처리하는 보다 정교한 로직을 필요로 합니다.

## 샌드위치 공격 방지

단순히 RPC URL에 `mev-protect=true` 쿼리 매개변수를 추가하여 통계적으로 샌드위치 공격과 연결된 검증자로부터 트랜잭션을 우회하세요 — 트랜잭션 로직에 변경은 없습니다:

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

<Card title="MEV 보호" icon="shield-halved" href="/docs/ko/sending-transactions/mev-protect">
  MEV 보호 작동 방식, 지원하는 방법 및 장단점을 확인하세요.
</Card>

## 트랜잭션에서 리베이트 받기

귀하의 트랜잭션이 생성하는 MEV의 일부를 자동으로 SOL로 지급받기 위해 참여할 수 있습니다 — 트랜잭션 로직에 변화 없음.

<Card title="트랜잭션 리베이트" icon="coins" href="/docs/ko/sending-transactions/backrun-rebates">
  `sendTransaction` 호출에 한 개의 매개변수를 추가하여 SOL 리베이트를 받기 시작합니다.
</Card>

## 관련 메서드

<CardGroup cols={2}>
  <Card title="sendTransaction" href="/docs/ko/api-reference/rpc/http/sendtransaction">
    서명된 트랜잭션을 네트워크에 전송
  </Card>

  <Card title="simulateTransaction" href="/docs/ko/api-reference/rpc/http/simulatetransaction">
    컴퓨트 유닛을 추정하기 위해 트랜잭션을 시뮬레이션
  </Card>

  <Card title="getSignatureStatuses" href="/docs/ko/api-reference/rpc/http/getsignaturestatuses">
    트랜잭션의 확인 상태 확인
  </Card>

  <Card title="getLatestBlockhash" href="/docs/ko/api-reference/rpc/http/getlatestblockhash">
    트랜잭션 서명을 위한 최신 블록 해시 얻기
  </Card>

  <Card title="getBlockHeight" href="/docs/ko/api-reference/rpc/http/getblockheight">
    만료 확인을 위한 현재 블록 높이 얻기
  </Card>
</CardGroup>
